如果调用代码只迭代集合,是否有任何理由将内部集合公开为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
我的问题与这个关于使用IEnumerable<T>vs的问题有关IReadOnlyCollection<T>.
我也经常习惯IEnumerable<T>将集合作为返回类型和参数公开,因为它既可以是不可变的,也可以是懒惰的.
但是,我越来越关注代码中地点的扩散,我必须枚举一个参数以避免ReSharper给出的可能的多个枚举警告.我理解为什么ReSharper建议这一点,我同意它建议的代码(下面)以确保封装(即,没有关于调用者的假设).
Foo[] arr = col as Foo[] ?? col.ToArray();
Run Code Online (Sandbox Code Playgroud)
但是,我发现此代码的重复性是污染性的,我同意一些IReadOnlyCollection<T>更好的替代方案,特别是本文中提出的观点,其中指出:
最近,我一直在考虑回归的优点和缺点
IEnumerable<T>.从积极的一面,它大约是最小的一个接口获得,所以给人们留下你的方法作者比承诺更重的替代需要更多的灵活性
IList<T>或(但愿)阵列.但是,正如我在上一篇文章中所概述的那样,
IEnumerable<T>回归诱使来电者违反Liskov替代原则.这太容易让他们使用LINQ扩展方法,如Last()和Count(),其语义IEnumerable<T>不答应.我们需要的是一种更好的方法来锁定一个返回的集合,而不会让这种诱惑如此突出.(我想起Barney Fife艰难地学习这一课.)
IReadOnlyCollection<T>在.NET 4.5中输入new.它只添加一个属性IEnumerable<T>:Count属性.通过承诺计数,你向你的来电者保证你IEnumerable<T>确实有一个终点.然后,他们可以使用LINQ扩展方法,如Last()清醒的良心.
但是,正如观察者可能已经注意到的那样,本文仅讨论使用IReadOnlyCollection<T>返回类型.我的问题是,相同的论点同样适用于将其用于参数吗?对此的任何理论思考或评论也将受到赞赏.
事实上,我认为使用的一般经验法则IReadOnlyCollection<T>是,如果使用的话,可能存在多次枚举(相对于ReSharper警告)IEnumerable<T>.否则,请使用IEnumerable<T>.
我对数据结构只有两个要求:
我知道这IReadOnlyList确实保留了秩序。我可以使用它,但我不需要索引。这意味着我应该使用IReadOnlyCollection. 不幸的是,我找不到它保持秩序的信息。
你知道吗?
我有一个私有设置为 的类List<string>,因此我无法设置此列表。
这是我的课:
public class PaginationReturn<T>
{
public PaginationReturn()
{
this.Errors = new List<string>();
this.Success = true;
}
public IEnumerable<T> Data { get; set; }
public Boolean Success { get; private set; }
public List<string> Errors { get; private set; }
public void AddError(String mensagem)
{
this.Errors.Add(mensagem);
this.Success = false;
}
}
Run Code Online (Sandbox Code Playgroud)
我不想允许做这样的事情,但这编译没有错误:
paginationReturn.Errors.Add("Error!!");
Run Code Online (Sandbox Code Playgroud)
我想强制使用此方法将项目添加到列表中:
paginationReturn.AddError("Error!!");
Run Code Online (Sandbox Code Playgroud)