2011-01-10 122 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

相關問題