我应该通过哪个接口公开List <t>?</t>

时间:2009-05-28 12:38:23

标签: c# .net c#-3.0 interface ilist

在对此question runefs的回复中建议“除非您有非常具体的理由使用IList,否则您应该考虑IEnumerable”。你用哪个?为什么?

6 个答案:

答案 0 :(得分:12)

IEnumberable<T>是只读的,您必须重新构建集合才能对其进行更改。另一方面,IList<T>是可读写的。因此,如果您希望对集合进行大量更改,请公开IList<T>,但如果可以安全地假设您不会对其进行修改,请使用IEnumerable<T>

答案 1 :(得分:7)

始终使用提供所需功能的最严格的界面,因为这为您提供了以后更改实施的最大灵活性。因此,如果IEnumerable<T>已足够,则使用该...如果您需要列表功能,请使用IList<T>

最好使用强类型通用版本。

答案 2 :(得分:4)

我遵循的原则是我读过一段时间的原则:

  

“消费最简单,并揭露   最复杂的“

(我确定这是非常常见的,我误报了它,如果有人知道你的来源,你可以发表评论或编辑吗......)

(编辑补充 - 嗯,这里我几周后,我刚刚在一个完全不同的背景下遇到这个引用,它看起来像是Robustness Principle或Postel定律 - < / p>

  

保守你所做的事;在你接受别人的事上要自由。

最初的定义是通过互联网进行网络通信,但我确信我已经看到它用于在OO中定义类合同。)

基本上,如果你要定义一个外部消费方法,那么参数应该是最基本的类型,为你提供所需的功能 - 在你的例子中,这可能意味着接受IEnumerable而不是IList。这为客户端代码提供了最大的灵活性。另一方面,如果您要公开一个属性以供外部使用,那么使用最复杂的类型(IList或ICollection而不是IEnumerable)这样做,因为这样可以为客户端提供最多的代码。他们使用对象的方式具有灵活性。


我发现自己和Dr.Jokepu之间的谈话很有吸引力,但我也很欣赏这不应该是一个讨论论坛,所以我会编辑我的答案,进一步概述我选择降压背后的原因趋势并建议您将其暴露为IList(实际上,正如您所见,列表)。让我们说这是我们正在讨论的课程:

public class Example
{
    private List<int> _internal = new List<int>();

    public /*To be decided*/ External
    {
        get { return _internal; }
    }
}

首先,让我们假设我们将External暴露为IEnumerable。我在其他答案和评论中看到的原因目前是:

  • IEnumerable是只读的
  • IEnumerable是事实上的标准
  • 它减少了耦合,因此您可以更改实施
  • 您不公开实施细节

虽然IEnumerable只公开只读功能,但不会使它只读。您返回的实际类型很容易通过反射或简单地暂停调试器并查找,因此将其强制转换回List&lt;&gt;,这同样适用于下面注释中的FileStream示例。如果你试图保护这个成员,那么假装它就不是其他方法了。

我不相信这是事实上的标准。我在.NET 3.5库中找不到任何代码,Microsoft可以选择返回具体集合并返回接口。由于LINQ,IEnumerable 中更常见,但这是因为它们不能公开更多派生类型,而不是因为它们不想这样做。

现在,减少我同意的耦合 - 一点 - 基本上这个论点似乎是你告诉客户端,当你返回的对象是我希望你对待的列表是一个IEnumerable,以防您决定稍后更改内部代码。忽略这个问题以及无论如何真实类型暴露的事实它仍然留下“为什么停止IEnumerable?”的问题。如果您将其作为对象类型返回,那么您将完全自由地将实现更改为任何内容!这意味着您必须已决定客户端代码需要多少功能,因此您要么编写客户端代码,要么基于任意指标做出决策。

最后,如前所述,您可以假设实现细节始终在.NET中公开,特别是如果您公开公开该对象。

所以,在那么长的dia骂之后还剩下一个问题 - 为什么要把它作为List&lt;&gt;?好吧,为什么不呢?你没有通过将它暴露为IEnumerable获得任何东西,那么为什么人为地限制客户端代码使用该对象的能力呢?想象一下,如果Microsoft已经确定Winforms控件的Controls集合应该显示为IEnumerable而不是ControlCollection - 您将无法再将其传递给需要IList的方法,处理任意索引的项目,或查看是否包含一个特定的控件,除非你施放它。微软实际上并没有获得任何收益,这只会给你带来不便。

答案 3 :(得分:3)

当我只需要枚举孩子时,我使用IEnumerable。如果我碰巧需要Count,我会使用ICollection。不过,我试图避免这种情况,因为它暴露了实现细节。

答案 4 :(得分:2)

IList<T>确实是一个非常强大的界面。我更喜欢公开Collection<T> - 派生类型。这与Jeffrey Richter建议做的几乎一致(附近没有书,所以不能指定页/章号):方法应该接受最常见的类型作为参数,并返回最“派生”的类型作为返回值。

答案 5 :(得分:1)

如果通过属性公开只读集合,那么传统的方法是将它公开为ReadOnlyCollection(或派生类),包装你拥有的任何东西。它向客户端公开了IList的全部功能,但它非常清楚它是只读的。