2011-01-10 123 views
0

我无法理解在IEnumerable上调用ToArray()时会发生什么。我一直认为只有参考被复制。当在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 
     }; 
} 

回答

4

问题如下。当执行行

var firstOne = stuff.First(); 

,集合collection1迭代并返回的Two一个新的实例。当执行线

var array = stuff.ToArray(); 

,收集collection再次迭代和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

4

.ToArray()这里是红鲱鱼。在您的Convert函数中,您正在创建Two的一个完全不相关的实例,并将其属性设置为布尔值(它是而不是的引用类型),您从One实例中获取该实例。对Two的新创建实例的任何更改将会影响One实例的而不是。它们在任何方面都没有关系。

如果您Convert这样做:

IEnumerable<One> Convert(IEnumerable<One> input) { 
    return from i in input 
      select i; 
} 

你会得到你所期望的结果。

+0

他实际上只是在转换的列表上工作,在这种情况下,类One对它没有任何影响 – Rob 2011-01-10 02:00:45

+0

@Rob:`One`是一个引用类型。在我的`Convert`版本中,没有`New One {..}`。它只是返回对同一个实例的引用。 – 2011-01-10 02:05:33

相关问题