如何防止方法调用者修改返回的集合?

Dan*_*ner 3 c# collections ienumerable readonly-collection

我有方法将私有集合返回给调用者,我想阻止调用者修改返回的集合.

private readonly Foo[] foos;

public IEnumerable<Foo> GetFoos()
{
    return this.foos;
}
Run Code Online (Sandbox Code Playgroud)

目前,私有集合是一个固定数组,但如果需要在运行时添加新项目,集合可能会成为一个列表.

有几种解决方案可以防止调用者修改集合.返回IEnumerable<T>是最简单的解决方案,但调用者仍然可以将返回值向上转换IList<T>并修改集合.

((IList<Foo>)GetFoos())[0] = otherFoo;
Run Code Online (Sandbox Code Playgroud)

克隆集合的明显缺点是有两个集合可以独立发展.到目前为止,我已经考虑了以下选项.

  1. 将收藏包装进去ReadOnlyCollection<T>.
  2. Enumerable通过执行类似的虚拟投影返回由类定义的LINQ迭代器之一list.Select(item => item).实际上我考虑使用Where(item => true)因为返回的迭代器似乎更轻量级.
  3. 编写自定义包装器.

我不喜欢使用ReadOnlyCollection<T>它是它实现IList<T>和调用Add()或访问索引器将导致异常.虽然这在理论上是绝对正确的,但几乎没有真正的代码检查IList<T>.IsReadOnlyIList<T>.IsFixedSize.

使用LINQ迭代器 - 我将代码包装在扩展方法中MakeReadOnly()- 防止这种情况,但它有一个黑客的味道.

编写自定义包装器?重新发明轮子?

有任何想法,考虑或其他解决方案吗?


在标记这个问题时,我发现了之前没有注意到的Stack Overflow问题.Jon Skeet也建议使用"LINQ hack",但使用效率更高Skip(0).

Jar*_*Par 5

不幸的是没有办法实现正是你在找什么在框架的当前版本.它根本没有具体类型和接口样式的可索引不可变/只读集合的​​概念.

正如您所指出的,ReadOnlyCollection<T>在混凝土类型方面可以正常工作.但是没有相应的接口可以实现,这也是静态只读的.

你真正的选择是......

  • 定义自己的集合类
  • 要么只实现IEnumerable<T>或定义集合实现的需要只读接口.