我偶然发现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
中实际使用匿名类型。我只是想知道它为什么不能按我认为的方式工作的原因。谢谢。
答案 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实例。