在C#中使用匿名类型迭代StringDictionary

时间:2016-04-20 07:44:59

标签: c# collections anonymous-types

我偶然发现System.Collections.Specialized.StringDictionary,并尝试使用var关键字迭代其条目,如下所示:

StringDictionary sd = new StringDictionary();

sd.Add("key", "value");
foreach(var v in sd)
{
    Console.WriteLine(v.Key);
}

我很惊讶地发现这会产生编译错误:

  

'对象'不包含' Key'的定义没有延伸   方法' Key'接受类型'对象'的第一个参数。可能   结果

当我使用System.Collections.DictionaryEntry代替var时,一切正常。我可以想象,由于某些原因,当使用匿名类型时,编译器将StringDictionary视为对象的集合,但我想知道原因。究竟发生了什么?

顺便说一句,我并不打算在foreach中实际使用匿名类型。我只是想知道它为什么不能按我认为的方式工作的原因。谢谢。

2 个答案:

答案 0 :(得分:3)

System.Collections.Specialized.StringDictionary是一个非常古老的课程。它已经存在于.NET Framework 1中,当时泛型还没有出现。因此,首先,当它被创建时,它只能实现非通用的IEnumerable接口,它不会告诉编译器任何有用的东西,其次,当它被创建时,{{1} }关键字还没有存在,所以你不得不输入var。当.NET 2.0出现并且泛型变得可用,并且C#3出现并且foreach (DictionaryEntry v in sd)关键字变得可用时,该类可能已经更新以实现通用接口,但是没有必要这样做,因为在那么你可以改用通用的var

答案 1 :(得分:2)

请注意var本身不是匿名类型。它是一个关键字,指示编译器推断类型。我会将var称为"推断类型"如果我不得不给它一个名字。它通常用于具有匿名类型的情况,因为您无法按名称引用其类型。但是,这不是这里的情况。

在这种情况下StringDictionary,实现非通用System.Collections.IEnumerable,它使用object作为当前项目的类型。因此,v的推断类型为object,其中没有属性Key。为类型插入DictionaryEntry会导致编译器插入强制转换。请注意,v的任何其他类型实际上都会编译,但在运行时会失败。

正如@hvd指出的那样,尴尬只是历史的一次意外。由于引入了泛型集合类型,因此无需更新StringDictionary,因此它现在是一种为向后兼容性而维护的历史工件。请考虑source中的文档注释:

  

将此类视为过时 - 使用Dictionary< String,String>而是使用适当的StringComparer实例。