我花了好几个小时思考曝光名单成员的问题。在一个与我类似的问题中,Jon Skeet 给出了一个非常好的答案。请随便看看。
用于公开成员集合的 ReadOnlyCollection 或 IEnumable?
我通常非常偏执于公开列表,特别是如果您正在开发 API 的话。
我一直使用 IEnumable 来公开列表,因为它非常安全,并且提供了很大的灵活性。让我举个例子:
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IEnumerable<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
任何针对 IEnumable 进行编码的人在这里都是相当安全的。如果我以后决定使用一个有序列表或其他东西,他们的代码都没有中断,这仍然是很好的。这样做的缺点是 IEnumable 可以被强制转换回此类之外的列表。
出于这个原因,许多开发人员使用 ReadOnlyCollection 来公开成员。这是相当安全的,因为它永远不会被抛回到列表中。对我来说,我更喜欢 IEnumable,因为它提供了更多的灵活性,如果我想实现一些不同于列表的东西。
我想到了一个我更喜欢的新点子。使用 IReadOnlyCollection:
public class Activity
{
private readonly IList<WorkItem> workItems = new List<WorkItem>();
public string Name { get; set; }
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return new ReadOnlyCollection<WorkItem>(this.workItems);
}
}
public void AddWorkItem(WorkItem workItem)
{
this.workItems.Add(workItem);
}
}
我觉得这保留了 IEnumable 的一些灵活性,并且封装得很好。
我发布这个问题是为了得到一些关于我的想法的意见。与 IEnumable 相比,您更喜欢此解决方案吗?您认为使用 ReadOnlyCollection 的具体返回值更好吗?这是一场激烈的辩论,我想试着看看我们都能想出哪些利弊。
提前谢谢你的意见。
剪辑
首先感谢大家对这里的讨论作出的贡献。我确实从每一个人身上学到了很多,我真诚地感谢你们。
我正在添加一些额外的情况和信息。
IReadOnlyCollection 和 IEnumable 有一些常见的缺陷。
考虑下面的例子:
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
即使接口是只读的,也可以将上面的示例强制转换回一个列表并进行修改。该接口,尽管与其同名,但并不保证不变性。由您来提供一个不可变的解决方案,因此您应该返回一个新的 ReadOnlyCollection。通过创建一个新列表(本质上是一个副本) ,对象的状态是安全可靠的。
里奇班在他的评论中说得最好: 一个界面只能保证某些东西能做什么,而不是它不能做什么。
下面是一个例子:
public IEnumerable<WorkItem> WorkItems
{
get
{
return new List<WorkItem>(this.workItems);
}
}
以上可以施放和变异,但你的对象仍然是不可变的。
另一个框外语句是集合类:
public class Bar : IEnumerable<string>
{
private List<string> foo;
public Bar()
{
this.foo = new List<string> { "123", "456" };
}
public IEnumerator<string> GetEnumerator()
{
return this.foo.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
上面的类可以具有按照您希望的方式对 foo 进行变异的方法,但是您的对象永远不能被强制转换为任何排序的列表并进行变异。
Carsten Fuhrmann 在 IEnumerables 中提出了一个关于收益率回报表的奇妙观点。
再次感谢大家。