【发布时间】:2020-05-17 05:16:20
【问题描述】:
由于SortedDictionary.ValueCollection 的Enumerator 的行为与其他枚举器的行为不同,我们最近遇到了一个错误。我设法将问题缩小到以下(无意义的)示例:
public void Example()
{
var sorted = new SortedDictionary<string, int>
{
{"1", 1 },
{"3", 3 },
{"0", 0 },
{"2", 2 },
{"4", 4 }
};
var fromValues = sorted.Values.GetEnumerator();
fromValues.MoveNext();
var fromLinq = sorted.Select(x => x.Value).GetEnumerator();
fromLinq.MoveNext();
var fromDictionary = new Dictionary<string, int>(sorted).Values.GetEnumerator();
fromDictionary.MoveNext();
for (var i = 0; i < 3; i++)
{
Console.WriteLine($"Printing for {i}");
Print(" From Values: ", fromValues, i);
Console.WriteLine(" ------------");
Print(" From Linq: ", fromLinq, i);
Console.WriteLine(" ------------");
Print(" From Dictionary: ", fromDictionary, i);
Console.WriteLine();
}
}
private void Print(string prefix, IEnumerator<int> enumerator, int value)
{
do
{
Console.WriteLine(prefix + "Value in loop: " + enumerator.Current);
if (enumerator.Current == value)
{
Console.WriteLine(prefix + "Selected Value: " + enumerator.Current);
break;
}
} while (enumerator.MoveNext());
}
这将产生以下输出:
Printing for 0
From Values: Value in loop: 0
From Values: Selected Value: 0
------------
From Linq: Value in loop: 0
From Linq: Selected Value: 0
------------
From Dictionary: Value in loop: 0
From Dictionary: Selected Value: 0
Printing for 1
From Values: Value in loop: 0
From Values: Value in loop: 1
From Values: Selected Value: 1
------------
From Linq: Value in loop: 0
From Linq: Value in loop: 1
From Linq: Selected Value: 1
------------
From Dictionary: Value in loop: 0
From Dictionary: Value in loop: 1
From Dictionary: Selected Value: 1
Printing for 2
From Values: Value in loop: 0
From Values: Value in loop: 2
From Values: Selected Value: 2
------------
From Linq: Value in loop: 1
From Linq: Value in loop: 2
From Linq: Selected Value: 2
------------
From Dictionary: Value in loop: 0
From Dictionary: Value in loop: 1
From Dictionary: Value in loop: 2
From Dictionary: Selected Value: 2
如您所见,三个Iterators 的行为不同:
- SortedDictionary:
Current在传递给函数时始终为 0,但MoveNext在循环中推送到正确的值。 - Linq:行为与我预期的
Iterator一致。 - 字典:每次将
Enumerator传递给函数时都会重置。
我怀疑SortedDictionary.ValueCollection.Enumerator 是一个结构,而 linq 产生的一个是引用类型这一事实与它有关。但这并不能解释为什么它不像 Dictionary 中的Enumerator。
【问题讨论】:
-
这确实很奇怪——.Net Core 也会发生这种情况
-
@MatthewWatson 简化复制的行为很清楚。
Enumerator是一个struct并且在每次调用PrintNextValue方法时,您都会传递它的副本,其中Current设置为0,即集合中的第一个元素。但它没有回答 OP 问题 -
与此同时,我找到了前往Jon Skeet 和Eric Lippert 的方法。但这并不能解释 SortedDictionary...