Eri*_*ebo 118 .net c# collections ienumerable readonly-collection
如果调用代码只迭代集合,是否有任何理由将内部集合公开为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);
Run Code Online (Sandbox Code Playgroud)
正如我所看到的,IEnumerable是ReadOnlyCollection接口的一个子集,它不允许用户修改集合.因此,如果IEnumberable接口足够,那么就是要使用的接口.这是推理它的正确方法还是我错过了什么?
谢谢/ Erik
Jon*_*eet 93
更现代的解决方案
除非您需要内部集合是可变的,否则您可以使用该System.Collections.Immutable包,将您的字段类型更改为不可变集合,然后直接公开它 - Foo当然,假设它本身是不可变的.
更新的答案更直接地解决问题
如果调用代码只迭代集合,是否有任何理由将内部集合公开为ReadOnlyCollection而不是IEnumerable?
这取决于您对调用代码的信任程度.如果您完全控制将要调用此成员的所有内容,并且您保证不会使用任何代码:
ICollection<Foo> evil = (ICollection<Foo>) bar.Foos;
evil.Add(...);
Run Code Online (Sandbox Code Playgroud)
那么肯定,如果你直接退回收藏品,不会造成任何伤害.我通常会尝试比这更偏执.
同样,正如你所说:如果你只需要 IEnumerable<T>,那么为什么要把自己绑在更强大的东西上呢?
原始答案
如果您使用的是.NET 3.5,则可以通过使用对Skip的简单调用来避免复制并避免简单的转换:
public IEnumerable<Foo> Foos {
get { return foos.Skip(0); }
}
Run Code Online (Sandbox Code Playgroud)
(还有很多其他选项可以轻松包装 - 关于SkipSelect/Where的好处是没有委托可以为每次迭代毫无意义地执行.)
如果您不使用.NET 3.5,您可以编写一个非常简单的包装器来执行相同的操作:
public static IEnumerable<T> Wrapper<T>(IEnumerable<T> source)
{
foreach (T element in source)
{
yield return element;
}
}
Run Code Online (Sandbox Code Playgroud)
Voj*_*vic 41
如果您只需要遍历集合:
foreach (Foo f in bar.Foos)
Run Code Online (Sandbox Code Playgroud)
然后返回IEnumerable就足够了.
如果您需要随机访问项目:
Foo f = bar.Foos[17];
Run Code Online (Sandbox Code Playgroud)
然后将它包装在ReadOnlyCollection中.
Stu*_*lar 31
如果你这样做,那么没有什么能阻止你的调用者将IEnumerable转换回ICollection然后修改它.ReadOnlyCollection消除了这种可能性,尽管仍然可以通过反射访问底层的可写集合.如果集合很小,那么解决此问题的一种安全且简单的方法是返回副本.
| 归档时间: |
|
| 查看次数: |
31874 次 |
| 最近记录: |