C#IEnumerable,ICollection,IList还是列表?

Pio*_*ula 1 ienumerable interface

谁能给我解释一下为什么我们不断地使用IEnumerable遍布C#的时候,我的逻辑,我们应该使用ListIListICollection代替。

查看此提交修复。 在此处输入图片说明

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

太好了,每个人都在重复这一点(我明白了),所以为什么我需要不断地ToList()对每个数据库进行调用,以防止在原始线程处理上下文时多线程陷入僵局。

当然,一旦查询被枚举为列表,我们应该从那里开始使用List以避免混淆,线程安全问题ToList(),并一遍又一遍地不断调用每个模型。

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

- 编辑

这个问题的一个重要方面是,我从不知道协方差和逆方差

List<IItem>由于List实现上的运行时问题,您无法执行此操作,因此必须使用IEnumarable<IItem>-仅在特定情况下有意义,即在两个不同系统上具有相同实体且需要使用一段代码的情况。否则,我List<>自问这个问题以来一直在使用,那大概90%的时间正确用于业务层。数据库/存储库层现在坚持使用IColletion或IQueryable。

ang*_*son 6

很难回答这个问题,因为它很容易发表意见,而不是回答。我会尽力的。

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

这是我对涵盖的API设计领域的特定观点的看法:

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

我会举几个例子。如果您的方法可以接受任何集合,请接受IEnumerable<T>。如果您的方法需要可索引的集合,请采用IList<T>或类似方法。如果该方法所做的第一件事是通过将输入转换为List .ToList(),请对其进行打开。如果我已经在外面有一个清单,并且想将其提供给您的方法,请采用List<T>

但是,我必须意识到一个事实,一旦您说了算IList<T>便可以修改列表。如果可以,请直接发送清单。否则,我将不得不.ToList() 在外面执行。这并不比以前更糟,这只是一个有关谁负责的问题。

相反,如果您的方法返回的对象是a List<T>,则将其返回为List<T>IList<T>。不要把它藏在后面IEnumerable<T>

在这里,您还应该知道,任何取回此列表的调用者都可以对其进行修改。如果这样不行,请不要将其返回为IList<T>

不过,您可以在最后一个示例中说,如果该列表不应该在外部进行修改,则在返回后(不是调用者列表),则应将其隐藏在后面IEnumerable<T>,但这仅是隐藏事实,程序员可以仍将其投射回IList<T>并对其进行修改。如果您不能接受,请通过发送副本.ToList()

但是,所有这些都归结为责任。

如果您的方法返回了IEnumerable<T>,不是我,正在编写使用该方法的代码的人,是否依赖于您的方法正常工作?如果您的方法由于已经处理了数据库上下文而无法使用,则取决于您,您的代码,错误,问题。

同样,如果我需要可以索引的内容,但除此之外,它是一个纯只读集合,则应设计我的方法以采用适当的集合接口来发出信号。如果设计要采用的方法IEnumerable<T>,我应该知道我是在专门说“我将采用任何懒惰产生的集合”。如果我不知道或不想这么说,那我就不要接受IEnumerable<T>

以便为您的特定代码行回答基本问题。在这里,您绝对必须.ToList()在内部调用,因为否则您的方法将损坏,出错或出错。

,您可以重新设计您的方法,使其保留其惰性特性,但在就绪之前不处理数据库上下文。在这方面,您对方法的简单更改将是使用yield return

using (var context = ... )
{
    foreach (var element in context.Request(...))
        yield return element;
}
Run Code Online (Sandbox Code Playgroud)

进行这样的更改后,您仍然要推迟访问数据库的实际成本,直到调用者实际遍历返回的集合,并且仍在正确处理上下文(假定调用者正确进行了迭代)。在这里,我仍然IEnumerable<T>要特别指出“我被懒洋洋地评价了”。

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


Kie*_*lin 0

IEnumerable 没有明确说明数据集是什么集合类型,因此您可以进行更通用的编程,而不是为特定类型提供特定函数。