为什么使用readonly IEnumerable <t> </t>

时间:2013-07-15 08:22:21

标签: c# ienumerable immutability readonly mutability

为什么要声明IEnumerable<T> readonly

从这个article on async & await我们得到以下代码。

class OrderHandler
{
    private readonly IEnumerable<Order> _orders;

    public OrderHandler()
    {
        // Set orders.
    }
    public IEnumerable<Order> GetAllOrders()
    {
        return _orders;
    }
}

IEnumerable<T>是不可变的。这与readonly关键字有什么不同?

3 个答案:

答案 0 :(得分:5)

此处的readonly关键字适用于字段_orders。它只是意味着在对象的生命周期内不能为字段分配不同的值。例如,这是不可能的:

class OrderHandler
{
    private readonly IEnumerable<Order> _orders;

    public OrderHandler()
    {
        // Set orders.
    }

    void SomeMethod()
    {
        _orders = new Order[0];
    }
}

您将收到此编译器错误:

  

无法分配readonly字段(构造函数或变量初始值设定项除外)

使该集合成为只读。例如,你仍然可以这样做:

class OrderHandler
{
    public readonly IEnumerable<Order> Orders;

    public OrderHandler()
    {
        Orders = new List<Order>();
    }
}

((List<Order>)OrderHandler.Orders).Add(new Order());

这可能违反了班级的线程安全性。有关不可变集合的信息,请参阅Tigran's answer

进一步阅读

答案 1 :(得分:4)

另外如果将_orders定义为不可变,则会添加该事件,这使得immutable只引用自身,而不是该集合的内容。我仍然可以在枚举中更改对象。

因此从C#5.0开始,我们将得到:

Immutable Collections in .NET Framework

引用文章:

  

不可变集合是保证它们永远不会的集合   改变他们的内容并完全线程安全

答案 2 :(得分:0)

正如其他人所说,readonly限定符使得引用存储在类对象的类类型字段中,一旦该对象的构造函数完成,就会不可变,但是没有这样的效果在引用可能引用的任何对象上。没有合理的方法,限定符可以通过这种方式影响引用引用的对象,因为引用的其他副本可以存储在没有这种限定符的字段中。

然而,这并不意味着readonly关键字无法有效地应用于可变对象。假设有一个类Foo,其字段stuff持有IEnumerable<KeyValuePair<int,string>>,并且有人希望它公开实现Keys的类型的属性IEnumerable<int>包含stuff中每个项目的关键部分。如果stuff保持只读字段,则Keys返回的包装器对象可以保存对stuff的引用,并具有对该集合进行任何更改的“实时视图”。但是,如果stuff不是只读字段,则包装器对象必须具有Foo的引用,如果要确保调用Keys属性它总是表现为实时视图。