C#IEnumerable,ICollection,IList还是列表? [英] C# IEnumerable, ICollection, IList or List?

查看:160
本文介绍了C#IEnumerable,ICollection,IList还是列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释为什么我们在C#上始终使用IEnumerable的原因,但根据我的逻辑,我们应该使用ListIListICollection.

Can somebody explain to me why we constantly use IEnumerable all over C# when, by my logic we should be using List,IList or ICollection instead.

查看此提交修复程序.

Look at this commit fix.

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

Ok, number 1) IEnumarable should only be used for read only collections!

太棒了,每个人都在重复(我明白),所以为什么我需要不断地在每个数据库调用上放置ToList(),以防止在原始线程处理上下文时多线程产生皱纹.

Great, everybody keeps repeating that (I get it), so why do I need to constantly need putting ToList() on every single database call to prevent mulit-threads creashing when the original thread disposes of context.

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

Surely once the query has been Enumarated to a List, we should just use List from there on to avoid confusion, thread safety issues and constantly calling ToList() on every single model, over and over.

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

Also on WebAPI that parse JSON, a text representation of an already enumerated object, we store it as IEnumarable again. We already know the size, we not interested in lazy loading it, we probably going to modify that object somewhere along the line, so why don't we store it as List of.

-编辑

关于此问题的一个重要方面是,我从未听说过协方差和自变量

One important aspect about this question is that I never knew about covariance and contravariance

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

You cannot do List<IItem> because of runtime problems on the List implementation so you have to use IEnumarable<IItem> - This will only make sense in specific cases where you have the same entity, on two different systems, that need to work on one piece of code. Otherwise I have been using List<> since asking the question and that is probably 90% of the time correct to use in business layers. Database/Repository layers stick to IColletion now or IQueryable.

推荐答案

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

It's kinda hard to answer this because it's very easy to post an opinion, and not an answer. I'll try though.

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

This is a fundamental question about responsibility, more specifically, good API design.

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

Here are my thoughts about the specific corner of the world of API design that this covers:

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

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

I'll give a few examples. If your method can take any collection, take IEnumerable<T>. If your method needs an indexable collection, take IList<T> or similar. If the first thing the method does is convert the input to a List through .ToList(), be open about it. If I already have a list on the outside and I want to give it to your method, take List<T>.

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

However, I must be aware of the fact that once you say you take IList<T>, you're able to modify the list. If that is OK, good, I can simply send you my list. Otherwise, I will have to execute .ToList() on the outside. This is not worse than before, it's simply a question about who is responsible for doing so.

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

On the opposite side, if your method returns an object that is a List<T>, return it as List<T> or IList<T>. Don't hide it behind IEnumerable<T>.

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

Here you should also be aware that any caller that gets this list back is able to modify it. If this is not OK, don't return it as IList<T>.

但是,您可以在最后一个示例中说,如果不应该在外部修改该列表,则返回后(不是呼叫者列表),则应将其隐藏在IEnumerable<T>后面,但这只会隐藏实际上,程序员仍然可以将其转换回IList<T>并进行修改.如果您不能接受,请通过.ToList()返回副本.

Though, you can say in that last example that if that list is not supposed to be modified on the outside, after returning (it's not the callers list), then you should hide it behind IEnumerable<T>, but this only hides the fact, the programmer can still cast it back to IList<T> and modify it. If you can't accept this, return a copy through .ToList().

但是,所有这些都可以归结为责任.

However, all of this goes back to responsibility.

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

If your method returns IEnumerable<T>, shouldn't I, the person writing code that is using this method, rely on your method working correctly? If your method won't work because you've already disposed of the database context, then that's on you, your code, your bug, your problem.

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

Likewise, if I need something that can be indexed into, but other than that is a purely readonly collection, I should design my method to take the appropriate collection interface to signal this. If I design my method to take IEnumerable<T>, I should know that I'm specifically saying "I'll take any lazily produced collection". If I don't know that, or don't want to say that, then I should not take IEnumerable<T>.

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

So as to answer the underlying question for your specific line of code. Here you absolutely must call .ToList() inside because otherwise your methods is broken, buggy, wrong.

OR ,您可以重新设计方法,使其保留其惰性特性,但在准备好数据库上下文之前不要对其进行处理.在这方面,您对方法的简单更改将是使用yield return:

OR, you can redesign your method in such a way that it retains its lazy nature, but doesn't dispose of the database context until it's ready. A simple change to your method in this regard would be to use yield return:

using (var context = ... )
{
    foreach (var element in context.Request(...))
        yield return element;
}

通过这样的更改,您仍将推迟到数据库的实际花费,直到调用者实际遍历返回的集合,并且仍在正确处理上下文(假设调用者进行了正确的迭代) .在这里,我仍然会返回IEnumerable<T>来专门说我被懒惰地评估了".

With such a change you're still postponing the actual cost of going to the database until the caller actually iterates over the collection you returned, and you're still disposing of the context correctly (assuming the caller does the iteration correct). Here I would still return IEnumerable<T> to specifically say "I'm lazily evaluated".

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

However, if the list that you produce internally is not kept, nobody is responsible for it, you're effectively giving the responsibility of this list to the caller, then absolutely should you return it as List<T>. Don't hide it behind IEnumerable<T>.

这篇关于C#IEnumerable,ICollection,IList还是列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆