2015-09-07 100 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; }; 
} 
相关问题