为什么List <t> .Add是只读属性中的读取机制?</t>

时间:2014-08-15 08:11:01

标签: c# properties

也许这只是一种误解,但对我来说这是一个很大的问题。让我解释一下:

根据reference,属性是一种机制,而不是一个字段。一种为字段提供读写函数的机制,根据this,我们可以使用getset访问器创建只读,只写或读写属性

现在实施就在这里:

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>不是只读的原因),我需要一个关于只读属性的解释。

4 个答案:

答案 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
    {
        // ...
    }
}