【发布时间】:2012-03-01 18:32:03
【问题描述】:
IEnumerable 不保证枚举两次会产生相同的结果。事实上,创建一个 myEnumerable.First() 在执行两次时返回不同值的示例非常容易:
class A {
public A(string value) { Value = value; }
public string Value {get; set; }
}
static IEnumerable<A> getFixedIEnumerable() {
return new A[] { new A("Hello"), new A("World") };
}
static IEnumerable<A> getDynamicIEnumerable() {
yield return new A("Hello");
yield return new A("World");
}
static void Main(string[] args)
{
IEnumerable<A> fix = getFixedIEnumerable();
IEnumerable<A> dyn = getDynamicIEnumerable();
Console.WriteLine(fix.First() == fix.First()); // true
Console.WriteLine(dyn.First() == dyn.First()); // false
}
这不仅仅是一个学术例子:使用流行的from ... in ... select new A(...) 将创建这种情况。这可能会导致意外行为:
fix.First().Value = "NEW";
Console.WriteLine(fix.First().Value); // prints NEW
dyn.First().Value = "NEW";
Console.WriteLine(dyn.First().Value); // prints Hello
我明白为什么会发生这种情况。我也知道这可以通过在 Enumerable 上执行 ToList() 或覆盖 A 类的 == 来解决。这不是我的问题。
问题是:当您编写一个采用任意 IEnumerable 的方法并且您希望序列只计算一次的属性(然后引用被“固定”)时,执行此操作的规范方法是什么? ToList() 似乎主要使用,但如果源已经固定(例如,如果源是数组),则引用将复制到列表中(不必要,因为我只需要固定属性)。有没有更合适的方法或者ToList() 是这个问题的“规范”解决方案?
【问题讨论】:
-
根据定义,IEnumerable 不是说不能保证顺序吗?如果您的实现需要订单,您使用的是错误的数据类型,不是吗?您在与 IEnumerable 的合同中所要求的只是元素可以遍历 IE:正如您所说,列表更适合。
标签: c# linq ienumerable