我有方法返回到调用方的私人集合,我想阻止调用方修改返回的集合。如何防止方法调用方修改返回的集合?
private readonly Foo[] foos;
public IEnumerable<Foo> GetFoos()
{
return this.foos;
}
目前私人收藏是固定阵列,但在今后如果需要在运行时增加新的项目产生的集合可能成为一个列表。
有几种解决方案可以防止调用者修改集合。返回IEnumerable<T>
是最简单的解决方案,但调用者仍然可以将返回值上传到IList<T>
并修改集合。
((IList<Foo>)GetFoos())[0] = otherFoo;
克隆集合有一个明显的缺点,即有两个集合可以独立演化。到目前为止,我已经考虑了以下选项。
- 包装在
ReadOnlyCollection<T>
集合。 - 通过执行像
list.Select(item => item)
这样的虚拟投影来返回Enumerable
类定义的LINQ迭代器之一。其实我考虑使用Where(item => true)
,因为返回的迭代器看起来更轻量级。 - 编写自定义包装。
我不喜欢使用ReadOnlyCollection<T>
什么是它实现IList<T>
,并呼吁Add()
或访问索引会导致异常。虽然理论上这是绝对正确的,但几乎没有真正的代码检查IList<T>.IsReadOnly
或IList<T>.IsFixedSize
。
使用LINQ迭代器 - 我用扩展方法包装代码MakeReadOnly()
- 阻止这种情况,但它具有破解的味道。
写一个自定义包装?重新发明轮子?
任何想法,考虑或其他解决方案?
虽然标注了这个问题,我发现this Stack Overflow question之前我没有注意到。 Jon Skeet也建议使用“LINQ hack”,但使用Skip(0)
更有效。
除非存在安全问题(潜在的敌对调用者),否则我通常不担心防止不明智转换或调用ReadOnlyCollection上的Add。愚蠢的开发人员也可以使用反射和访问内部。代码防白痴是很困难的。目标是防止无辜使用公共接口。 – TrueWill 2010-01-22 20:56:40