ReadOnlyCollection 或 IEnumerable 用于公开成员集合?
如果调用代码仅迭代集合,是否有任何理由将内部集合公开为 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 接口足够了,那么就可以使用它。 这是推理的正确方式还是我错过了什么?
Is there any reason to expose an internal collection as a ReadOnlyCollection rather than an IEnumerable if the calling code only iterates over the collection?
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);
As I see it IEnumerable is a subset of the interface of ReadOnlyCollection and it does not allow the user to modify the collection. So if the IEnumberable interface is enough then that is the one to use. Is that a proper way of reasoning about it or am I missing something?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
更现代的解决方案
除非您需要内部集合是可变的,否则您可以使用
System.Collections.Immutable
包,将字段类型更改为不可变集合,然后直接公开它 - 假设Foo
本身是不可变的, 当然。更新了答案以更直接地解决问题
这取决于您对调用代码的信任程度。 如果您完全控制将调用此成员的所有内容,并且您保证没有任何代码会使用:
那么当然,如果您直接返回集合,则不会造成任何损害。 不过,我通常会尝试变得更加偏执一点。
同样,正如您所说:如果您只需要
IEnumerable
,那么为什么要把自己绑在更强大的东西上呢?原始答案
如果您使用的是.NET 3.5,您可以避免制作副本并通过使用对 Skip 的简单调用来避免简单转换:(
还有很多其他方法简单包装的选项 -
Skip
over Select/Where 的好处是每次迭代都没有毫无意义地执行的委托。)如果您不使用 .NET 3.5,您可以编写一个非常简单的包装器做同样的事情:
More modern solution
Unless you need the internal collection to be mutable, you could use the
System.Collections.Immutable
package, change your field type to be an immutable collection, and then expose that directly - assumingFoo
itself is immutable, of course.Updated answer to address the question more directly
It depends on how much you trust the calling code. If you're in complete control over everything that will ever call this member and you guarantee that no code will ever use:
then sure, no harm will be done if you just return the collection directly. I generally try to be a bit more paranoid than that though.
Likewise, as you say: if you only need
IEnumerable<T>
, then why tie yourself to anything stronger?Original answer
If you're using .NET 3.5, you can avoid making a copy and avoid the simple cast by using a simple call to Skip:
(There are plenty of other options for wrapping trivially - the nice thing about
Skip
over Select/Where is that there's no delegate to execute pointlessly for each iteration.)If you're not using .NET 3.5 you can write a very simple wrapper to do the same thing:
如果您只需要迭代集合:
那么返回 IEnumerable 就足够了。
如果您需要随机访问项目:
则将其包装在 ReadOnlyCollection 中。
If you only need to iterate through the collection:
then returning IEnumerable is enough.
If you need random access to items:
then wrap it in ReadOnlyCollection.
如果您这样做,那么就没有什么可以阻止您的调用者将 IEnumerable 强制转换回 ICollection,然后对其进行修改。 ReadOnlyCollection 消除了这种可能性,尽管仍然可以通过反射访问底层可写集合。 如果集合很小,那么解决此问题的一种安全且简单的方法是返回副本。
If you do this then there's nothing stopping your callers casting the IEnumerable back to ICollection and then modifying it. ReadOnlyCollection removes this possibility, although it's still possible to access the underlying writable collection via reflection. If the collection is small then a safe and easy way to get around this problem is to return a copy instead.
我尽可能避免使用 ReadOnlyCollection,它实际上比仅使用普通列表要慢得多。
看这个例子:
I avoid using ReadOnlyCollection as much as possible, it is actually considerably slower than just using a normal List.
See this example:
有时您可能想要使用接口,也许是因为您想在单元测试期间模拟集合。 请参阅我的博客文章,了解如何使用以下命令将您自己的界面添加到 ReadonlyCollection一个适配器。
Sometimes you may want to use an interface, perhaps because you want to mock the collection during unit testing. Please see my blog entry for adding your own interface to ReadonlyCollection by using an adapter.