为什么使用只读 IEnumerable

本文关键字:IEnumerable 只读 为什么 | 更新日期: 2023-09-27 18:22:16

为什么要声明IEnumerable<T> readonly

从这篇关于 async & await 的文章中,我们有以下代码。

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

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

为什么使用只读 IEnumerable<T>

此处的 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 的答案。

延伸阅读

  • 只读(C# 参考(

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

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

.NET Framework 中的不可变集合

引用文章:

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

正如其他人所指出的,一旦对象的构造函数完成,readonly限定符使存储在类对象的类类型字段中的引用不可变,但对引用可能引用的任何对象都没有这种影响。 没有合理的方法可以使限定符以这种方式影响引用所引用的对象,因为引用的其他副本可能存储在没有此类限定符的字段中。

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