我无法理解在IEnumerable上调用ToArray()时会发生什么。我一直以为只复制了引用。
我希望这里的输出是: 真正 真
但我得到了 真正 假
这里发生了什么?
class One {
public bool Foo { get; set; }
}
class Two
{
public bool Foo { get; set; }
}
void Main()
{
var collection1 = new[] { new One(), new One() };
IEnumerable<Two> stuff = Convert(collection1);
var firstOne = stuff.First();
firstOne.Foo = true;
Console.WriteLine (firstOne.Foo);
var array = stuff.ToArray();
Console.WriteLine (array[0].Foo);
}
IEnumerable<Two> Convert(IEnumerable<One> col1) {
return
from c in col1
select new Two() {
Foo = c.Foo
};
}
答案 0 :(得分:4)
.ToArray()
在这里是红鲱鱼。在Convert
函数中,您正在创建一个完全不相关的Two
实例,并将其属性设置为布尔值(不是参考你从One
实例获取的。对新创建的Two
实例的任何更改都将不影响One
实例。它们没有任何关联。
如果您Convert
这样做了:
IEnumerable<One> Convert(IEnumerable<One> input) {
return from i in input
select i;
}
你会得到你期望的结果。
答案 1 :(得分:4)
问题如下。当行
var firstOne = stuff.First();
执行,迭代集合collection1
并返回Two
的新实例。当行
var array = stuff.ToArray();
被执行,集合collection
被迭代AGAIN并返回Two
的新实例,包括集合的第一个元素的新实例。特别是,这是一个与firstOne
不同的实例。因此,Object.ReferenceEquals(firstOne, array[0])
是false
的情况(注意,如上所述,Object.ReferenceEquals(stuff.First(),stuff.First())将是false
)。这就是您所看到的问题的原因。
要解决这个问题,你应该说
IEnumerable<Two> stuff = Convert(collection1).ToList();
或
IEnumerable<Two> Convert(IEnumerable<One> col1) {
return col1.Select(x => new Two { Foo = x.Foo}).ToList();
}
所以无论哪种方式,collection1
只迭代一次,然后Object.ReferenceEquals(firstOne, array[0])
将true
。