在通用方法中获取更复杂类型的正确类型推断

时间:2010-10-26 17:22:25

标签: c# type-inference generics

我在.NET 2.0框架中工作。我有一些代码工作,只是希望它更优雅地工作。

我需要有效地“镜像”一个Dictionary对象,这样如果我们从像这样的对象开始

Dictionary<TKey,TValue> StartDictionary;

我们可以像这样镜像

Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);

我们最终会得到一个新词典,每个KeyValuePair都会交换值和键

在有人问我原因之前:源代码很大并且在我的程序加载时从反射调用加载一次。我不想再次运行相同的反射调用来加载镜像字典。在我看来,创建一个镜像词典并按照我提出的方式填充其值和键,可以降低成本。

因此,作为那种不喜欢重写事物的人,我决定在帮助器类中编写一个Generic方法,我必须使用Generics来做Mirror。

现在请注意,我之前为普通标量类型编写了简单的通用方法

这就是我提出的

 public static TOutDic MirrorDictionary<TInDic, TOutDic>(TInDic InDictionary)
  where TInDic : IDictionary
  where TOutDic : IDictionary
{
  Type[] KVPTypes = typeof(TInDic).GetGenericArguments();
  Type TKey = KVPTypes[0];
  Type TValue = KVPTypes[1];
  Type TDic = typeof(Dictionary<,>).MakeGenericType(TValue, TKey);
  IDictionary OutDic = (IDictionary)Activator.CreateInstance(TDic);
  foreach (DictionaryEntry DE in (IDictionary)InDictionary) OutDic.Add(DE.Value, DE.Key);
  return (TOutDic)OutDic;
}

稍微有点但它有效,加载键和值的类型并创建镜像词典的实例

然后循环遍历InDictionary的基本DictionaryEntries,它将项添加到OutDic并返回它,将其转换为预期的类型

编译得很好

现在,当我去打电话的时候,我会想到,当我为标量类型调用Generic方法时,我可以使用上面的代码snippits说

Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);

但那不能编译给我

  

无法从用法推断出MirrorDictionary(TInDic)方法的类型参数。尝试明确指定类型参数。

所以如果我这样称呼它

      Dictionary<TValue, TKey> MirrorDic = MirrorDictionary<Dictionary<Tkey, TValue>, Dictionary<TValue,TKey>>(StringDic);

它的编辑和工作就像一个魅力。

现在的问题是,当传入Type并且传递出的Type是这个例子中的复杂类型时,如何正确推断传递给此方法的Type?

4 个答案:

答案 0 :(得分:1)

这是一个3.5解决方案(你也可以在VS2008和LinqBridge的2.0中使用它)

IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    return dict.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
}

纯粹的2.0解决方案

IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    Dictionary<TValue, TKey> newDict = new Dictionary<TValue, TKey>();
    foreach(KeyValuePair<TKey, TValue> kvp in dict)
    {
        newDict.Add(kvp.Value, kvp.Key);
    }
    return newDict;
}

类型推断应该适用于两种解决方案(因为它们具有相同的签名)

答案 1 :(得分:1)

通过告诉编码器键和值类型,可以使编译器的生活更轻松:

public static Dictionary<TValue, TKey> MirrorDictionary<TKey, TValue>
    (Dictionary<TKey, TValue> source)
{
    Dictionary<TValue, TKey> destination = new Dictionary<TValue, TKey>();

    foreach (KeyValuePair<TKey, TValue> kvp in source)
    {
        destination.Add(kvp.Value, kvp.Key);
    }

    return destination;
}

我认为你根本不需要反思。

样本用法:

static void Main(string[] args)
{
    Dictionary<int, string> source = new Dictionary<int, string>();
    source.Add(3, "foo");
    source.Add(4, "bar");

    DumpDic(source);

    DumpDic(MirrorDictionary(source));

    Console.ReadLine();

}

其中DumpDic是:

public static void DumpDic<TK, TV>(Dictionary<TK, TV> dic)
{
    foreach (KeyValuePair<TK, TV> keyValuePair in dic)
    {
        Console.WriteLine("{0} => {1}", keyValuePair.Key, keyValuePair.Value);
    }
}

答案 2 :(得分:0)

您可以将Out字典定义为out参数。类型推断不会查看您要分配的变量的类型,只会查看参数的类型。这就是无法编译的原因。

答案 3 :(得分:0)

你需要告诉它TValue和TKey是什么。除非它们在调用此代码的方法的签名中定义,否则它们没有任何特定类型。你需要给它类似的东西:

Dictionary<string, int> MirroredDictionary = MirrorDictionary(StartDictionary);