我有将私有集合返回给调用者的方法,我想阻止调用者修改返回的集合。
private readonly Foo[] foos;
public IEnumerable<Foo> GetFoos()
{
return this.foos;
}
目前私有集合是一个固定数组,但将来如果需要在运行时添加新项目,该集合可能会变成一个列表。
有几种解决方案可以防止调用者修改集合。返回IEnumerable<T>
是最简单的解决方案,但调用者仍然可以向上转换返回值IList<T>
并修改集合。
((IList<Foo>)GetFoos())[0] = otherFoo;
克隆集合具有明显的缺点,即有两个集合可以独立进化。到目前为止,我已经考虑了以下选项。
- 将集合包装在
ReadOnlyCollection<T>
. - 通过
Enumerable
执行虚拟投影(如list.Select(item => item)
. 实际上我考虑使用Where(item => true)
因为返回的迭代器看起来更轻量级。 - 编写自定义包装器。
我不喜欢使用ReadOnlyCollection<T>
的是它实现IList<T>
和调用Add()
或访问索引器会导致异常。虽然这在理论上是绝对正确的,但几乎没有真正的代码检查IList<T>.IsReadOnly
或IList<T>.IsFixedSize
.
使用 LINQ 迭代器 - 我将代码包装在扩展方法中MakeReadOnly()
- 可以防止这种情况,但它有一种 hack 的味道。
编写自定义包装器?重新发明轮子?
有什么想法、考虑或其他解决方案吗?
在标记这个问题时,我发现了这个我以前没有注意到的Stack Overflow 问题。Jon Skeet 也建议使用“LINQ hack”,但使用Skip(0)
.