我花了好几个小时思考揭露名单成员的问题.在一个与我类似的问题中,乔恩·斯基特给出了一个极好的答案.请随便看看.
ReadOnlyCollection or IEnumerable for exposing member collections?个
我通常对公开列表非常偏执,尤其是在开发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的一些灵活性,并且封装得相当好.
我发布这个问题是为了得到一些关于我 idea 的信息.比起IEnumerable,你更喜欢这个解决方案吗?您认为使用ReadOnlyCollection的具体返回值更好吗?这是一场相当激烈的辩论,我想试着看看我们都能想出哪些优点/缺点.
提前感谢您的意见.
EDIT
首先,感谢大家为本次讨论做出的贡献.我确实从每一个人身上学到了很多,我想真诚地感谢你们.
我正在添加一些额外的场景和信息.
IReadOnlyCollection和IEnumerable有一些常见的缺陷.
请考虑以下示例:
public IReadOnlyCollection<WorkItem> WorkItems
{
get
{
return this.workItems;
}
}
即使接口是只读的,上面的示例也可以转换回列表并进行变异.尽管该接口与其同名,但并不能保证其不变性.提供一个不可变的解决方案取决于您,因此您应该返回一个新的ReadOnlyCollection.通过创建新列表(实质上是副本),您的对象的状态是安全的.
Richiban在他的 comments 中说得最好:一个接口只保证某些东西能做什么,而不是不能做什么.
请参见下面的示例:
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 Führmann)在IEnumerables中提出了一个关于yield 率-yield 率声明的奇妙观点.
再次感谢大家.