也许这只是一种误解,但对我来说这是一个很大的问题。让我解释一下:
根据reference,属性是一种机制,而不是一个字段。一种为字段提供读写函数的机制,根据this,我们可以使用get
和set
访问器创建只读,只写或读写属性
现在实施就在这里:
public class Foo
{
private List<string> _bar;
public List<string> Bar
{
get
{
return _bar;
}
}
public Foo()
{
_bar = new List<string>();
_bar.Add("string1");
}
}
在Foo
类中,我们有一个只读属性(Bar
),由一个字符串组成。
现在让我们为这个类添加一个驱动程序:
static void Main(string[] args)
{
Foo fooObj = new Foo();
fooObj.Bar.Add("string2");
foreach (string s in fooObj.Bar)
{
Console.WriteLine(s);
}
Console.ReadLine();
}
这是一个很大的问号:
为什么Bar
属性不是只读的?
输出:
srring1
string2
我知道如何创建一个只读集合(我的问题不是List<T>
不是只读的原因),我需要一个关于只读属性的解释。
答案 0 :(得分:5)
Bar
属性是只读的,即无法直接设置
fooObj.Bar = new List<string>(); // compiler error
但是,该属性返回的数据不是
fooObj.Bar.Add("..."); // is fine
要理解的一点是属性上的修饰符决定了如何从对象访问,它对属性的基础数据没有直接影响。因此,从只读属性返回引用类型与从读/写属性返回引用类型完全相同。
在您的示例中,如果您希望Bar
是只读的,那么您可以返回ReadOnlyCollection<T>
这是一个不可变的集合,而不是List<T>
。
private List<string> _bar;
...
public void Add(string item)
{
_bar.Add(item);
}
public IEnumerable<string> Bar
{
get { return new ReadOnlyCollection<string>(_bar); }
}
这将使用包含对象控制列表,但允许您返回列表本身的只读副本。
答案 1 :(得分:1)
因为Bar
属性的 getter 方法返回列表,然后您正在改变该列表。省略 setter 方法只会阻止您分配一个像这样的新列表:
fooObj.Bar = new List<string>();
如果你想让它变成不可变的,你可以改变你的属性的返回类型为IEnumerable<string>
。虽然你仍然可以将它转换为列表然后变异......
答案 2 :(得分:1)
Bar
属性是只读。您只能阅读Bar
点列表 - 您无法将Bar
指向其他列表。
但是,列表本身是 mutable 。您可以在其中添加或删除项目。
Eric lippert在他的博文Immutability in C# Part One: Kinds of Immutability中称之为“浅薄的不变性”。该属性是只读的,但其内容可能会更改。
答案 3 :(得分:1)
好,
List<T>
是参考类型。
所以,属性
List<string> SomeList
{
get
{
// ...
}
}
是只读属性,您无法将SomeList
设置为其他List<string>
。从本质上讲,
SomeList = new List<string>();
不会编译。
如您所知,将引用类型的属性设置为只读不会使该类型为只读。
如果你想要一个我建议的只读列表,
IReadOnlyList<string> SomeList
{
get
{
// ...
}
}