C# 枚举作为ICollection的IDictionary.Keys集合<;T>;
我希望我不会因为问了这么简单的问题而被责骂。我可以在谷歌上搜索答案,但我想听听不是课本上写的东西 我正在编写一个单元测试来验证我的C# 枚举作为ICollection的IDictionary.Keys集合<;T>;,c#,.net,enumeration,C#,.net,Enumeration,我希望我不会因为问了这么简单的问题而被责骂。我可以在谷歌上搜索答案,但我想听听不是课本上写的东西 我正在编写一个单元测试来验证我的IDictionary键是否是顺序键 由于Keys属性是一个ICollection,因此我想枚举集合并将键值打印到控制台 尝试使用简单的for循环打印键值时: for (int i = 0; i < unPivotedData.Count; i++) { Console.WriteLine(unPivotedData.Keys[i]); } forea
IDictionary
键是否是顺序键
由于Keys
属性是一个ICollection
,因此我想枚举集合并将键值打印到控制台
尝试使用简单的for
循环打印键值时:
for (int i = 0; i < unPivotedData.Count; i++)
{
Console.WriteLine(unPivotedData.Keys[i]);
}
foreach(int key in unPivotedData.Keys)
{
Console.WriteLine(key);
}
一切都很顺利
我了解索引器的功能和实现方式,但是foreach
如何工作?我不明白foreach
如何工作,但是for
会导致编译器错误
我是否缺少一个基本的枚举
干杯
编辑:
此外,两者之间是否存在性能差异?我知道我不能将
for
与IDictionary一起使用,但如果我使用的是IList,我可以。for
的移动速度是否比foreach
快,或者性能增益是否可以忽略foreach
只是需要IEnumerable
;而对于(a,b,c)(在您的情况下)的需要索引器属性
当您对实现了IEnumerable
的对象调用foreach
时,它在引擎盖下调用GetEnumerator()
,这将返回一个对象。该对象实现了一些成员,如MoveNext()
和Current
。foreach
的每次迭代实际上都在调用MoveNext()
,如果枚举数可以向前移动,则返回true
,如果枚举数不能向前移动,则返回false(到达末尾)
这里的关键是,实现IEnumerable
的对象不知道它有多少项,它所在项的索引,等等。它所知道的只是它可以向前移动到下一项,将其作为当前项返回,直到项目用完为止
另一方面,(A,b,c)的循环本质上是永远循环的-即它不受您可能要迭代的集合的约束(尽管在实践中通常是这样)。在最基本的级别上,它每次执行一次C
,并检查B
是否为真。如果B
为真,它将再次循环。如果它是假的,它将停止。每次它循环时,在循环内您可能正在调用object[number]
,如果您的对象没有这样的属性,当然会失败
这里的关键是带有索引器的对象支持随机访问——这意味着您可以在任何时候调用[任意索引]
并获取该索引。与此相对应的是,IEnumerable
,后者同样只能访问当前项。Foreach使用IEnumerable接口。在“帮助”中查看它的定义,您将了解它的含义 foreach通过IEnumerable接口,该接口只提供一个自定义枚举器。有关信息,请参阅
基本上,它是一种自定义链表类型的东西,带有“当前”和“下一步移动”。从C#文档中读取。正如其他人所述,foreach使用集合的枚举器,因此
foreach(int key in unPivotedData.Keys)
{
Console.WriteLine(key);
}
翻译成这样:
IEnumerator enumerator = unPivotedData.Keys.GetEnumerator()
while(enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
正如你所看到的,这里面没有索引。索引是一种与迭代器完全不同的beast,迭代器可用于迭代目的(正如您在for循环中尝试的那样),但迭代器不能仅用于索引迭代键集合没有索引,因为根据字典的定义,元素的顺序无法保证。不幸的是,这也意味着您正在编写的单元测试的目的根本上是有缺陷的。您可以像这样思考IList
(支持索引)和IEnumerable
之间的区别:
如果我有一个房间,房间里的物品散落在地板上,我让你帮我取回房间里的所有物品,你可以进去,开始不按特定顺序捡起物品并把它们扔给我。秩序并不重要;重要的是你要检查所有的项目。从这个意义上讲,房间中的对象可以抽象地认为是实现了IEnumerable
接口。然后,如果我把所有物品都扔回房间,让你再做一次,当你第二次检查它们时,不能保证你会按照相同的顺序捡起它们。本质上,这是因为问“房间里的第n项是什么”是没有意义的
这是关于IEnumerable
的一个重要注意事项:尽管我从未见过foreach
在每次调用中不使用相同顺序的情况,但也不一定非得如此
另一方面,如果我按照特定的顺序将对象放入房间,并要求您按照我放置它们的相同顺序进去拾取它们,那么为每个对象指定一个数字是有意义的。“我放在房间里的第n件东西是什么?”这个问题在这种情况下是有意义的。因此,在此场景中,房间中的对象可能被认为实现了IList
接口
IEnumerator enumerator = unPivotedData.Keys.GetEnumerator()
while(enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}