【问题标题】:Why should I return IList<T> over List<T>? [duplicate]为什么我应该返回 IList<T> 而不是 List<T>? [复制]
【发布时间】:2011-07-03 18:21:24
【问题描述】:

可能重复:
C# - List<T> or IList<T>

到处都写着你应该从你的方法中返回IList&lt;T&gt;,而不是List&lt;T&gt;,但我找不到任何真正好的理由。我一直在寻找执行此操作的代码,然后调用代码通常会执行以下两项操作之一:

  1. 调用new List&lt;T&gt;(returnedIList),这样它就可以使用 List 上的所有好方法
  2. 转换回List&lt;T&gt;,这样它就可以使用 List 上的所有好方法

第一个很笨重,第二个会抛出 (runtime) InvalidCastException 如果实现实际上更改为其他东西(这使得它完全愚蠢) .

如果我使用List&lt;T&gt; 并且由于某种原因必须用我无法从List&lt;T&gt; 继承的IList&lt;T&gt; 的实现来替换它,那么我会遇到构建错误并且必须更改一些代码。这可能不太可能发生,如果发生这种情况,修复的工作量并不大。对于这种不太可能发生的情况,当然不值得失去List&lt;T&gt; 的好处和/或必须强制转换/新建List&lt;T&gt;(存在、查找等)来让它们回来吗?

那么,返回IList&lt;T&gt;还有其他原因吗?

【问题讨论】:

  • 不仅是“写满了”,这个问题已经被问及回答了!
  • 道歉 - 经过 3 页的结果后,我放弃了寻找 - 所以“相关性”最近对我来说似乎有点不对劲!回答这个问题:stackoverflow.com/questions/400135/c-listt-or-ilistt/… ;D
  • 不需要道歉,搜索 SO 的用处有限。我在 Google 上搜索了 site:stackoverflow.com!找到骗子!
  • 嘿,好主意。虽然如果 SO 搜索不太好,我很惊讶他们自己没有使用 Google API :(

标签: c# .net generics interface


【解决方案1】:

原因是你的方法可以与任何实现IList&lt;T&gt; 的东西一起使用,而不仅仅是一个列表。然而,更糟糕的是,自从 Linq 出现以来,我已经开始让很多东西返回 Enumerable&lt;T&gt; 甚至只是 IEnumerable

不过,我不确定我是否理解其中的困难。如果某些东西正在返回一个实际列表,并且它的返回取决于那个,或者它的用途是特定于那个的,那么它应该返回List&lt;T&gt;。如果没有,那么您应该不需要将其转换为列表。

【讨论】:

  • 我怀疑调用代码是在方法之后编写的,程序员不愿意更改方法以返回具体 List - 我正在尝试了解该决定是否合理。
【解决方案2】:

这个想法是让调用者决定他们将使用什么集合。您会看到很多人尽可能返回IEnumerable&lt;T&gt;。这样做通常被认为是一种很好的做法。返回 IList 让调用者在返回 List 时使用他们喜欢的任何 IList 实现,要求他们在他们选择的数据集合中手动复制 List 的数据。

返回 IEnumerable 是理想的。

【讨论】:

  • 我不明白返回 IList 如何让调用者决定实现(我们正在谈论返回,而不是接受作为参数,如果这就是你的意思)
  • 我将以 IEnumerable 为例,因为更多类实现了该接口。当我调用一个返回 IEnumerable 的方法时,我可以决定只通过它进行 foreach() 或创建一个 List/Queue/Stack/SortedList 等。它允许我使用我喜欢的 IEnumerable 接口的实现。另一方面,返回列表迫使我要么使用列表,要么创建堆栈,例如手动输入堆栈中列表中的每个项目。
  • 如果我返回 List 你也可以创建任何这些(因为 List 是 IEnumerable)!
【解决方案3】:

在我看来,您正在查看一些质量较差的代码。

返回IList&lt;T&gt; 而不是List&lt;T&gt; 可以让您的代码更加灵活。您可以将实现替换为实现IList&lt;T&gt; 的任何集合,而不会破坏任何调用代码。这是一件好事……但只有当IList&lt;T&gt; 中定义的功能符合您的需求时。

您可以概括地说,您应该始终返回尽可能通用的类型。在大多数情况下,您可以使用IEnumerable&lt;T&gt;,但如果您需要更多功能,那么IList&lt;T&gt; 可以工作。如果这不能解决问题,请返回具体类型并完成它。

在您提到的两种情况下,都需要使用IList&lt;T&gt; 未直接提供的东西(如果没有,那么这两种方法都是错误的)。在这些情况下,方法应该返回 List&lt;T&gt; 以提供所需的功能,或者调用者应该使用其他方法。

【讨论】:

  • 是的!这正是每个人所说的最佳实践。然而,可能是因为我大部分时间都在使用更面向更高抽象级别的功能(如业务规则)的代码,所以在过去的 12 年中我没有遇到过这样的情况改变实施。但是,我可以看到当您处理实现 list 的类并且您希望此类被其他一些使用 IList 而不是 List 有好处的情况下继承的情况。
【解决方案4】:

如果可能的话,你真的应该返回 IEnumerable,否则返回 IList。

原因是您将来可能想要使用 List 以外的其他东西。实现自己的实现 IList 的列表并不少见,然后您不需要更改大部分代码。

从 IList 中搜索派生类型,您会发现仅在 .NET 框架内就获得了很多成功!

【讨论】:

  • IEnumerable 不适用于这些代码的大部分功能(我很想更改它 - 一方面,当我们可以通过结果“流式传输”时,我讨厌将所有内容加载到内存中)。如果我们要实现一个自定义列表,我想我们更有可能从 List 开始而不是滚动整个事情?
  • IEnumerable 实际上是返回可能最终用作列表的内容的好方法,因为可以从 IEnumerable 直接创建新列表(就像您的第一个示例一样)。我不能肯定地说,但我怀疑这样做的开销与直接返回一个新的 List 对象相比是零。返回 IEnumerable 的东西应该用yield 实现,因此实际上不会创建任何新的列表对象。因此,无论哪种方式,您实例化一个列表并向其添加元素的次数都是相同的。
  • 是的,我知道 IEnumerable 并不总是符合要求,但如果确实如此,您可以突然使用诸如固定数组和 IQuerables 之类的东西,一旦您掌握了这将有很大帮助习惯了。更高级的列表根本不需要扩展 List,一个例子可能是延迟加载列表,它的存储策略与 List 完全不同 - 所以是的 List 可能是基础,但我通常不使用它(在这种情况下我包装它而是)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-02-10
  • 1970-01-01
  • 1970-01-01
  • 2012-06-23
  • 2012-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多