Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 枚举作为ICollection的IDictionary.Keys集合<;T>;_C#_.net_Enumeration - Fatal编程技术网

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