ReadonlyCollection,是不可变的对象
本文关键字:对象 不可变 ReadonlyCollection | 更新日期: 2023-09-27 18:11:28
我正在尝试使用ReadOnlyCollection使对象不可变,我希望对象的属性是不可变的。
public ReadOnlyCollection<FooObject> MyReadOnlyList
{
get
{
return new ReadOnlyCollection<FooObject>(_myDataList);
}
}
但是我有点困惑。
我试图改变对象的属性在MyReadOnlyList使用foreach和…我可以改变值属性,它是正确的吗?我理解ReadOnlyCollection设置了一个add级别,使对象不可变。
ReadOnlyCollection
是不可变的这一事实意味着集合不能被修改,即不能从集合中添加或删除任何对象。这并不意味着它包含的对象是不可变的。
ReadOnlyCollection
是一个不可变的facade,它可以读取底层集合(_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所指出的,这两个struct都不允许修改集合中元素的属性。这是因为结构体是值类型,当您访问一个元素时,集合返回该值的副本。您只能修改Point
类型的属性,如果它是一个类,这将意味着返回对实际对象的引用,而不是其值的副本。
我试图将对象的属性更改为MyReadOnlyList使用foreach和…我可以改变值属性,它是正确的吗?我ReadOnlyCollection设置一个添加级别来创建对象不可变的。
使用ReadOnlyCollection
对存储在集合中的对象没有任何保证。它所保证的是集合一旦被创建就不能被修改。
如果您想使您的FooObject
不可变,那么只需这样做:
public class FooObject
{
public FooObject(string someString, int someInt)
{
SomeString = someString;
SomeInt = someInt;
}
public string SomeString { get; };
public int SomeInt { get; };
}
不可变的是集合本身,而不是对象。目前,c#不支持不可变对象,除非像ReadOnlyCollection<T>
那样对它们进行包装。
你仍然可以创建不可变对象,如果它们的属性没有可访问的setter。顺便说一句,它们根本不是不可变的,因为它们可以从具有与setter相同或更高可访问性的类成员中变异。
// 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";
}
正如我前面说过的,引用类型在定义上总是可变的,在某些条件下,它们可以表现为不可变的。
最后,结构体是不可变的,但它们是值类型,不应该仅仅因为它们可以表示不可变数据而使用它们。关于为什么结构是不可变的,请参阅本问答:为什么c#结构是不可变的?