代码之家  ›  专栏  ›  技术社区  ›  Euro Micelli

我应该使用像IEnumerable这样的接口,还是像List这样的具体类<>

  •  4
  • Euro Micelli  · 技术社区  · 16 年前

    我最近在其他地方表达了我的观点*,但我认为它值得进一步分析,所以我将其作为自己的问题发布。

    假设我需要在程序中创建并传递一个容器。至少在现阶段,我可能对一种容器和另一种容器没有强烈的意见,但我确实选择了一种;为了便于讨论,假设我将使用 列表<> .

    问题是: 编写我的方法来接受并返回高级接口(如C#)是否更好 数不清的 ? 或者我应该编写方法来获取并传递我选择的特定容器类。

    我应该寻找什么因素和标准来决定?什么样的项目能从中受益?计算机语言会影响你的决定吗?表演程序大小?个人风格?

    (这有关系吗?)

    **(家庭作业:找到答案。但是在你寻找我的答案之前,请把你的答案贴在这里,以免对你产生偏见。)*

    6 回复  |  直到 16 年前
        1
  •  16
  •   Rex M    16 年前

    您的方法应该始终接受执行其函数所需的最不特定的类型。如果您的方法需要枚举,请接受 IEnumerable .如果需要的话 IList<> -具体的事情,根据定义,你必须给它一个 IList<> .

        2
  •  5
  •   Matt Hamilton    16 年前

    唯一应该影响你的决定的是你计划如何使用这个参数。如果你只是在它上面迭代,使用 IEnumerable<T> .如果您正在访问索引成员(例如 var x = list[3] )或者以任何方式修改列表(例如 list.Add(x) )然后使用 ICollection<T> IList<T> .

        3
  •  3
  •   TofuBeer    16 年前

    总有一个权衡。一般的经验法则是尽可能高层次地声明事物。因此,如果您只需要访问IEnumerable中的方法,那么这就是您应该使用的方法。

    最近的另一个SO问题示例是采用文件名而不是文件*(或文件描述符)的C API。在那里,文件名严格限制了可以传递的内容(有许多内容可以通过文件描述符传递,但只有一个具有文件名)。

    一旦你必须开始铸造,你要么太高,要么你应该制作第二种方法,采用更具体的类型。

    我能想到的唯一例外是,当速度是绝对必须的,并且您不想花费虚拟方法调用的费用时。声明特定类型可以消除虚拟函数的开销(这取决于语言/环境/实现,但作为一个可能正确的通用语句)。

        4
  •  3
  •   Daniel Earwicker    16 年前

    是与我的讨论引发了这个问题,所以我已经知道了我的答案,但答案就在这里!:)

    我认为Linq to Objects已经为这个问题提供了一个很好的答案。通过对一系列项目使用最简单的接口,它为您如何实现该序列提供了最大的灵活性,允许延迟生成,在不牺牲性能的情况下提高生产力(不是真正意义上的)。

    不成熟的抽象确实会有代价——但主要是发现/发明新抽象的代价。但是,如果你已经有了非常好的产品,那么不利用它们就太疯狂了,这就是通用集合接口提供给你的。

    有些人会告诉你,公开一个类中的所有数据“更容易”,以防你需要访问它。同样,Euro建议最好使用一个丰富的容器接口,比如 IList<T> (甚至是混凝土类) List<T> )然后再收拾残局。

    但我认为,正如最好隐藏不想访问的类的数据成员,以便以后可以轻松修改该类的实现,因此应该使用最简单的接口来引用一系列项。在实践中,从暴露一些简单和基本的东西开始,然后再“放松”它,比从一些松散的东西开始,努力给它施加秩序要容易得多。

    所以假设 IEnumerable<T> 表示一个序列就行了。那么在那些你需要 Add Remove 项(但仍不需要通过索引查找),使用 IContainer<T> ,继承了 IEnumerable<T> 这样就可以与其他代码完美地互操作。

    通过这种方式,就可以非常清楚地(仅从局部检查某些代码)该代码将能够对数据做什么。

    的确,小程序需要更少的抽象。但如果他们成功了,他们往往会成为大项目。如果他们首先使用简单的抽象,这就容易多了。

        5
  •  0
  •   Quintin Robinson    16 年前

    这的确很重要,但正确的解决方案完全取决于使用情况。如果你只需要做一个简单的枚举,那么一定要使用IEnumerable,这样你就可以通过任何实现者来访问你需要的功能。然而,如果你需要列表功能,并且你不想创建一个新的列表实例,如果碰巧每次调用该方法时,传递的可枚举项不是列表,那么就使用列表。

        6
  •  0
  •   Community CDub    7 年前

    我回答了一个类似的C#问题 here 1.我认为你应该尽可能提供最简单的合同,在我看来,在托收的情况下,这通常是可以计算的。

    实现可以由内部BCL类型提供——可以是Set、Collection、List等等——其所需的成员由您的类型公开。

    抽象类型始终可以继承简单的BCL类型,这些类型由具体类型实现。在我看来,这允许你坚持 LSP 更容易的。