2015-09-07 46 views
2

我想使用ReadOnlyCollection使對象不可變,我想對象的屬性是不可變的。ReadonlyCollection,對象是不可變的嗎?

public ReadOnlyCollection<FooObject> MyReadOnlyList 
{ 
    get 
    { 
     return new ReadOnlyCollection<FooObject>(_myDataList); 
    } 
} 

但是我有點困惑。

我嘗試使用foreach在改變對象的屬性MyReadOnlyList和...我可以改變value屬性,是正確的嗎?我瞭解ReadOnlyCollection設置了一個添加級別,使對象不可變。

回答

6

ReadOnlyCollection是不可變的事實意味着該集合不能被修改,即不能添加或從集合中刪除對象。這並不意味着它包含的對象是不可變的。

This article作者:Eric Lippert,解釋了不同種類的不變性是如何工作的。基本上,ReadOnlyCollection是一個不可改變的外觀,可以讀取底層集合(_myDataList),但無法修改它。但是,您仍然可以更改基礎集合,因爲您可以通過執行諸如_myDataList[0] = null之類的操作來參考_myDataList

此外,由ReadOnlyCollection返回的對象與由_myDataList返回的對象相同,即this._myDataList.First() == this.MyReadOnlyList.First()(具有LINQ)。這意味着如果_myDataList中的對象是可變的,那麼MyReadOnlyList中的對象也是可變的。

如果您希望對象不可變,您應該相應地設計它們。例如,你可以使用:代替

public struct Point 
{ 
    public Point(int x, int y) 
    { 
     this.X = x; 
     this.Y = y; 
    } 

    // In C#6, the "private set;" can be removed 
    public int X { get; private set; } 
    public int Y { get; private set; } 
} 

public struct Point 
{ 
    public int X { get; set; } 
    public int Y { get; set; } 
} 

編輯:在這種情況下,如Ian Goldby指出,無論是結構允許修改集合中的元素的屬性。發生這種情況是因爲結構是值類型,當您訪問元素時,集合會返回該值的副本。如果它是一個類,則只能修改Point類型的屬性,這意味着將返回對實際對象的引用,而不是其值的副本。

+0

其實,如果在ReadOnlyCollection對象是結構,而不是類,然後他們有效地只讀的集合,因爲訪問一個元素給你一個* boxed *結構。你不能直接修改它(「不能修改拆箱轉換的結果」),如果你將它賦給本地結構變量,你會得到一個副本。 (儘管您仍然可以通過Items屬性修改ReadOnlyCollection。) –

+0

如果集合是泛型並返回類型爲「T」的元素,爲什麼集合返回的值會被裝箱?除此之外,我更新了我的答案,說集合中的結構是有效的,因爲你只能得到它們的值的副本。 –

+0

我懷疑這是框架的優化,以防止剛剛讀取的結構副本。當然,如果你編寫'roList [i] .X = 5',編譯器會抱怨「無法修改拆箱轉換的結果」。如果編譯器沒有這樣做,那麼'x = roList [i] .X'總是需要爲了讀取一個屬性而創建一個完整的結構副本。 –

0

不可變的是集合本身,而不是對象。就目前而言,C#不支持不可變對象,因爲ReadOnlyCollection<T>在你的情況下並不包含它們。

嗯,你仍然可以創建一個不可改變的對象,如果它們的屬性沒有訪問的制定者。順便說一下,它們不是永恆不變的,因爲它們可以從一個可能具有相同或更多可訪問性的類成員進行變異。

// Case 1 
public class A 
{ 
    public string Name { get; private set; } 

    public void DoStuff() 
    { 
     Name = "Whatever"; 
    } 
} 

// Case 2 
public class A 
{ 
    // This property will be settable unless the code accessing it 
    // lives outside the assembly where A is contained... 
    public string Name { get; internal set; } 
} 

// Case 3 
public class A 
{ 
    // This property will be settable in derived classes... 
    public string Name { get; protected set; } 
} 

// Case 4: readonly fields is the nearest way to design an immutable object 
public class A 
{ 
    public readonly string Text = "Hello world"; 
} 

正如我之前所說,引用類型總是被定義可變的,他們可以表現在一定條件下與成員國無障礙扮演一成不變的。

最後,結構是不變的,但他們是值類型,他們不應該被使用,只是因爲他們可以代表不可改變的數據。見這種問答&一個更多地瞭解爲什麼結構是不變的:Why are C# structs immutable?

+0

我在書中紅色,但我認爲這是錯誤的> System.Collections.ObjectModel.ReadOnlyCollection 類型是包裝一個集合和導出該數據的只讀版本的標準方式 – lunatic84

+0

@ lunatic84該定義說明我的答案正在努力爲你解決。該集合是不可變的,但數據仍然是可變的。 –

1

我嘗試使用foreach在改變對象的屬性MyReadOnlyList 和...我可以改變價值屬性,這是否正確? I 瞭解ReadOnlyCollection設置了一個添加級別,使對象 不可變。

使用ReadOnlyCollection不保證存儲在集合中的對象。它所保證的是,集合一旦創建就不能被修改。如果從中檢索到一個元素,並且它具有可變屬性,則可以很好地修改它。

如果你想使你的FooObject一個不變的一個,然後簡單地這樣做:

public class FooObject 
{ 
    public FooObject(string someString, int someInt) 
    { 
     SomeString = someString; 
     SomeInt = someInt; 
    } 

    public string SomeString { get; }; 
    public int SomeInt { get; }; 
} 
相關問題