C#IEnumerable,ICollection,IList还是List?

时间:2017-06-29 11:57:49

标签: interface ienumerable

有人可以向我解释为什么我们经常使用IEnumerable来自C#,根据我的逻辑,我们应该使用ListIListICollection

看看这个提交修复。 enter image description here

好的,数字1)IEnumarable只能用于只读集合!

很好,每个人都在不断重复(我明白了),所以为什么我需要经常需要在每个数据库调用上放置ToList()以防止在原始线程处理上下文时多线程崩溃。

当查询被枚举到List时,我们应该只使用List来避免混淆,线程安全问题,并且不断地在每个模型上调用ToList(),一遍又一遍。

同样在解析JSON(已经枚举的对象的文本表示)的WebAPI上,我们再次将其存储为IEnumarable。我们已经知道了大小,我们对延迟加载不感兴趣,我们可能会修改该对象的某个位置,所以为什么我们不将它存储为List of。

- 编辑

关于这个问题的一个重要方面是我从未了解过covariance and contravariance

由于List实现上的运行时问题,您无法执行List<IItem>,因此您必须使用IEnumarable<IItem> - 这仅适用于在两个不同系统上具有相同实体的特定情况,需要处理一段代码。否则我一直在使用List<>,因为提出问题并且可能有90%的时间在商业层中使用正确。数据库/存储库层现在坚持IColletion或IQueryable。

2 个答案:

答案 0 :(得分:4)

有点难以回答这个问题,因为发表意见非常容易,而不是答案。我会尝试。

这是关于责任的基本问题,更具体地说,是良好的API设计。

以下是我对API设计世界特定角落的看法:

  • 在输出类型中尽可能具体。
  • 尽可能在输入类型中打开

我举几个例子。如果您的方法可以进行任何收集,请执行IEnumerable<T>。如果您的方法需要可索引的集合,请使用IList<T>或类似方法。如果该方法所做的第一件事是通过.ToList()将输入转换为List,那么请打开它。如果我已经在外面有一个列表,并且我想添加到您的方法中,请执行List<T>

但是,我必须知道,一旦您说出IList<T>,您就可以修改列表。如果可以,那很好,我可以直接发给你我的清单。否则,我将不得不在外部执行.ToList() 。这并不比以前更糟糕,它只是一个关于谁负责这样做的问题。

另一方面,如果您的方法返回List<T>的对象,请将其返回为List<T>IList<T>。不要将其隐藏在IEnumerable<T>后面。

在这里你还应该知道任何获得此列表的调用者都可以修改它。如果不是这样,请不要将其作为IList<T>返回。

尽管如此,你可以在最后一个例子中说,如果该列表不应该在外部修改,在返回之后(它不是调用者列表),那么你应该将它隐藏在{{1}之后但是这只隐藏了这个事实,程序员仍然可以将它强制转换回IEnumerable<T>并修改它。如果您无法接受此操作,请通过IList<T>返回副本。

但是,所有这些都可以追溯到责任。

如果您的方法返回.ToList(),那么编写使用此方法的代码的人依赖于正常工作的方法吗?如果您的方法因为您已经处理了数据库上下文而无法工作,那么这就是您,您的代码,您的错误,您的问题。

同样,如果我需要可以索引的东西,但除此之外是纯粹的只读集合,我应该设计我的方法来采取适当的集合接口来发出信号。如果我设计我的方法来取IEnumerable<T>,我应该知道我特意说&#34;我将采取任何懒惰的制作集合&#34;。如果我不知道,或者不想这么说,那么我就不应该IEnumerable<T>

为了回答特定代码行的基本问题。在这里你绝对必须在里面调用IEnumerable<T>,否则你的方法会被破坏,错误,错误。

,您可以重新设计方法,使其保持其惰性,但在准备好之前不会处置数据库上下文。在这方面对您的方法进行简单的更改将是使用.ToList()

yield return

通过这样的更改,您仍然会推迟转到数据库的实际成本,直到调用者实际迭代您返回的集合,并且您仍然正确处理上下文(假设调用者执行了此操作)迭代正确)。在这里,我仍然会回复using (var context = ... ) { foreach (var element in context.Request(...)) yield return element; } 专门说&#34;我懒得评价&#34;。

但是,如果您没有保留内部生成的列表,则没有人对此负责,您有效地将此列表的责任交给调用者,那么绝对应该将其作为IEnumerable<T>返回。不要将其隐藏在List<T>后面。

答案 1 :(得分:0)

IEnumerable没有明确说明数据集的集合类型,因此您可以执行更多通用编程,而不是具体特定类型的函数。