在IEnumerable上调用ToArray()时会发生什么?

时间:2011-01-10 01:35:56

标签: c#

我无法理解在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
        };
}

2 个答案:

答案 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