我花了好几个小时思考一下暴露名单成员的话题。在与我类似的问题中,乔恩·斯基特(Jon Skeet)给出了一个很好的答案。请随时查看。
ReadOnlyCollection或IEnumerable用于公开成员集合?
我通常对公开列表非常偏执,尤其是在开发API时。
我一直使用IEnumerable公开列表,因为它非常安全,并且具有很大的灵活性。让我在这里使用示例:
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);
}
}
任何针对IEnumerable进行编码的人在这里都是非常安全的。如果以后我决定使用有序列表或其他东西,它们的代码都不会中断,而且还是不错的。IEnumerable的缺点是可以将其强制转换回此类之外的列表。
因此,许多开发人员使用ReadOnlyCollection公开成员。这是非常安全的,因为它永远都不能返回列表。对我来说,我更喜欢IEnumerable,因为它提供了更多的灵活性,如果我想实现不同于列表的东西的话。
我提出了一个我更喜欢的新主意。使用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);
}
}
我觉得这保留了IEnumerable的一些灵活性,并且封装得很好。
我发布了这个问题,以征询我的想法。您是否喜欢此解决方案而不是IEnumerable?您认为使用ReadOnlyCollection的具体返回值更好吗?这是一场辩论,我想尝试看看我们所有人都能提出哪些优点/缺点。
预先感谢您的输入。
编辑
首先,感谢大家为这里的讨论做出了很大贡献。我确实从每一个人中学到了很多东西,并衷心感谢您。
我要添加一些其他方案和信息。
IReadOnlyCollection和IEnumerable有一些常见的陷阱。
考虑下面的示例:
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
即使接口是只读的,也可以将上面的示例转换回列表并进行突变。尽管具有相同的名称,但该接口不能保证不变性。您需要提供一个不变的解决方案,因此您应该返回一个新的ReadOnlyCollection。通过创建新列表(本质上是副本),对象的状态是安全无虞的。
Richiban在他的评论中说得最好:界面只能保证某些事情可以做,而不能保证它不能做。
参见以下示例:
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进行突变的方法,但是您的对象永远不能转换为任何种类的列表并进行突变。
卡斯滕·弗曼(CarstenFührmann)对IEnumerables中的收益回报表提出了奇妙的观点。
再次谢谢大家。