如果调用代码只对集合进行迭代,那么是否有任何理由将内部集合公开为ReadOnlyCollection而不是IEnumerable?

class Bar
{
    private ICollection<Foo> foos;

    // Which one is to be preferred?
    public IEnumerable<Foo> Foos { ... }
    public ReadOnlyCollection<Foo> Foos { ... }
}


// Calling code:

foreach (var f in bar.Foos)
    DoSomething(f);

在我看来,IEnumerable是ReadOnlyCollection接口的子集,它不允许用户修改集合.因此,如果IEnumberable接口足够,那么它就是可以使用的接口.这是正确的推理方式还是我遗漏了什么?

谢谢/埃里克

推荐答案

More modern solution

除非需要内部集合是可变的,否则可以使用System.Collections.Immutable包,将字段类型更改为不可变集合,然后直接公开该集合——当然,假设Foo本身是不可变的.

Updated answer to address the question more directly

如果调用代码只对集合进行迭代,那么是否有任何理由将内部集合公开为ReadOnlyCollection而不是IEnumerable?

这取决于您对调用代码的信任程度.如果您完全控制了所有调用此成员的内容,并且您拥有guarantee个代码无法使用的权限:

ICollection<Foo> evil = (ICollection<Foo>) bar.Foos;
evil.Add(...);

当然,如果你直接归还藏品,不会造成任何伤害.不过,我通常会试着变得更偏执一点.

同样,正如你所说:如果你只有10IEnumerable<T>,那么为什么要把自己绑在更强的东西上呢?

Original answer

如果你正在使用.NET 3.5,您可以通过使用一个简单的调用跳过来避免复制and避免简单的强制转换:

public IEnumerable<Foo> Foos {
    get { return foos.Skip(0); }
}

(对于琐碎的包装,还有很多其他选项--Skip比Select/WHERE好的一点是,没有 for each 迭代毫无意义地执行委托.)

如果你没有使用.NET 3.5您可以编写一个非常简单的包装器来完成同样的工作:

public static IEnumerable<T> Wrapper<T>(IEnumerable<T> source)
{
    foreach (T element in source)
    {
        yield return element;
    }
}

.net相关问答推荐

.NET 7.0中的UseHttpsRedirection和IIS生产部署

为什么我在环境变量中有不同的值?

您可以为 Func 或 Action 类型的函数或子参数指定默认值吗?

使用 PostAsJsonAsync C# 时出现错误请求

双精度的 C++ 和 C# 十六进制值之间的差异

查找 2 个已知值之间的字符串

"投掷;" 是什么意思?靠自己做什么?

即时窗口中的动态导致Microsoft.CSharp.RuntimeBinder.Binder未定义或导入错误

在生产中使用实体框架(代码优先)迁移

.NET 的 `Array.Sort()` 方法使用的排序算法是稳定的算法吗?

来自奥尔森时区的 .NET TimeZoneInfo

防止对话框在按钮的单击事件处理程序中关闭

app.config 文件和 XYZ.settings 文件有什么区别?

C# 中基于接口编程的运算符重载

Dapper 是否支持 SQL 2008 表值参数?

ILookup 接口与 IDictionary

我应该如何删除 DbSet 中的所有元素?

忽略 LINQ to XML 中的命名空间

序列化和反序列化 .NET 对象的最快方法

如何将两个 List 相互比较?