在通用方法中获得更复杂类型的适当类型推断

问题描述:

我正在.NET 2.0框架中工作。我有一些代码工作,只是希望它更加优雅一点。在通用方法中获得更复杂类型的适当类型推断

我有一个需要有效地“镜子” Dictionary对象,例如,如果我们有这样的

Dictionary<TKey,TValue> StartDictionary; 

的对象开始,我们可以镜像像这样

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

,我们将结束在每个KeyValuePair上都要交换一个新的字典,每个KeyValuePair都被交换。在任何人问我为什么之前,源字典相当大并且从re加载一次当我的程序加载时,flection调用。我不想再次运行相同的反射调用来加载镜像字典。创建一个镜像字典并按照我提出的方式填充它的值和密钥在我看来似乎成本更低。

因此,作为一种讨厌重写事物的人,我决定在助手类中编写泛型方法,我必须使用泛型来完成镜像。

现在想起你,我以前也写过简单的通用方法一般标量类型

这就是我想出了

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并返回它将其转换为预期的类型

编译就好现在

当我去调用它,我会在我所说的通用方法,我可以只使用我们的代码标量型觉得就像snippits上面说

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

但是,不编译给我

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

所以,如果我把它而不是像这样

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

它编译和作品就像一个魅力。

现在的问题变成如何正确地推断传入此方法的类型时传入的类型和传出的类型是复杂的类型,如在此示例中?

+0

它如何可以推断TOutDic当输入参数仅供TInDic类型的信息? – 2010-10-26 17:27:20

您可以让生活更轻松编译器通过告诉它的键和值类型如下:

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); 
    } 
} 
+0

我试过,首先它不会为我编译出于某种原因让我回去重试它,也许当我第一次创建该方法时,我可能会搞砸了。我会在测试后重新发布 – TofuBug 2010-10-26 17:40:40

+0

Yep完全冲过方法声明并忘记声明我的类型,因此当我需要公共静态字典时,公共静态Dictionary MirrorDictionary(Dictionary InDictionary) MirrorDictionary (Dictionary InDictionary) – TofuBug 2010-10-26 17:46:58

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

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

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

这不会帮助编译器推断TOutDic的类型,并且此行提供相同的编译器错误。 – stevemegson 2010-10-26 17:40:16

+0

@stevemegson - 不,在进一步阅读之后,它甚至没有接近,我很想删除它,但在我想让它给别人留下评论的机会之后。 – 2010-10-26 17:44:31

+0

我会收回downvote然后,我只是懒得downvote,因为单一upvote使它成为当时的最佳答案。 – stevemegson 2010-10-26 17:52:05

这里有一个3.5的解决方案

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

和纯2.0解决方案(你也可以在2.0与VS2008和LinqBridge使用它)

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; 
} 

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

+0

除了避免反射外,这也强制输入和输出类型是正确的。没有什么可以阻止你将原始方法调用为'MirrorDictionary ,Dictionary >(input)',它会很好地编译,但在运行时会导致无效的转换。 – stevemegson 2010-10-26 17:47:30