我应该总是返回IEnumerable 而不是IList 吗?

时间:2022-09-10 23:48:17

When I'm writing my DAL or other code that returns a set of items, should I always make my return statement:

当我正在编写我的DAL或其他返回一组项目的代码时,我是否应该总是返回语句:

public IEnumerable<FooBar> GetRecentItems()

or

public IList<FooBar> GetRecentItems()

Currently, in my code I have been trying to use IEnumerable as much as possible but I'm not sure if this is best practice? It seemed right because I was returning the most generic datatype while still being descriptive of what it does, but perhaps this isn't correct to do.

目前,在我的代码中,我一直试图尽可能地使用IEnumerable,但我不确定这是否是最佳实践?这似乎是正确的,因为我返回了最通用的数据类型,同时仍然描述它的作用,但也许这是不正确的。

13 个解决方案

#1


It really depends on why you are using that specific interface.

这实际上取决于您使用该特定界面的原因。

For example, IList<T> has several methods that aren't present in IEnumerable<T>:

例如,IList 有几个IEnumerable 中不存在的方法:

  • IndexOf(T item)
  • Insert(int index, T item)
  • Insert(int index,T item)

  • RemoveAt(int index)

and Properties:

  • T this[int index] { get; set; }
  • 这个[int index] {get;组; }

If you need these methods in any way, then by all means return IList<T>.

如果您以任何方式需要这些方法,那么一定要返回IList

Also, if the method that consumes your IEnumerable<T> result is expecting an IList<T>, it will save the CLR from considering any conversions required, thus optimizing the compiled code.

此外,如果使用IEnumerable 结果的方法期望IList ,它将保留CLR不考虑所需的任何转换,从而优化编译的代码。

#2


Framework design guidelines recommend using the class Collection when you need to return a collection that is modifiable by by the caller or ReadOnlyCollection for read only collections.

当您需要返回可由调用者或ReadOnlyCollection为只读集合修改的集合时,框架设计指南建议使用类Collection。

The reason this is preferred to a simple IList is that IList does not inform the caller if its read only or not.

这是一个简单的IList首选的原因是IList不通知调用者它是否只读。

If you return an IEnumerable<T> instead, certain operations may be a little trickier for the caller to perform. Also you no longer will give the caller the flexibility to modify the collection, something that you may or may not want.

如果您返回IEnumerable ,则某些操作可能对调用者来说有点棘手。此外,您不再为调用者提供修改集合的灵活性,这可能是您可能想要或不想要的。

Keep in mind that LINQ contains a few tricks up its sleeve and will optimize certain calls based on the type they are performed on. So, for example, if you perform a Count and the underlying collection is a List it will NOT walk through all the elements.

请记住,LINQ包含一些技巧,并会根据执行的类型优化某些调用。因此,例如,如果您执行Count并且基础集合是List,则它不会遍历所有元素。

Personally, for an ORM I would probably stick with Collection<T> as my return value.

就个人而言,对于ORM,我可能会将Collection 作为我的返回值。

#3


That depends...

Returning the least derived type (IEnumerable) will leave you the most leeway to change the underlying implementation down the track.

返回最少派生类型(IEnumerable)将为您提供最大的余地,以便在轨道上更改底层实现。

Returning a more derived type (IList) provides the users of your API with more operations on the result.

返回更多派生类型(IList)为API的用户提供了对结果的更多操作。

I would always suggest returning the least derived type that has all the operations your users are going to need... so basically, you first have to deremine what operations on the result make sense in the context of the API you are defining.

我总是建议返回最少派生的类型,它包含你的用户将需要的所有操作......所以基本上,你首先必须在你定义的API的上下文中去除对结果的哪些操作有意义。

#4


In general, you should require the most generic and return the most specific thing that you can. So if you have a method that takes a parameter, and you only really need what's available in IEnumerable, then that should be your parameter type. If your method could return either an IList or an IEnumerable, prefer returning IList. This ensures that it is usable by the widest range of consumers.

通常,您应该要求最通用,并返回最具体的内容。因此,如果你有一个带参数的方法,并且你只需要IEnumerable中可用的那个,那么那应该是你的参数类型。如果您的方法可以返回IList或IEnumerable,则更喜欢返回IList。这确保了最广泛的消费者可以使用它。

Be loose in what you require, and explicit in what you provide.

在你需要的东西上松散,并明确你所提供的东西。

#5


One thing to consider is that if you're using a deferred-execution LINQ statement to generate your IEnumerable<T>, calling .ToList() before you return from your method means that your items may be iterated twice - once to create the List, and once when the caller loops through, filters, or transforms your return value. When practical, I like to avoid converting the results of LINQ-to-Objects to a concrete List or Dictionary until I have to. If my caller needs a List, that's a single easy method call away - I don't need to make that decision for them, and that makes my code slightly more efficient in the cases where the caller is just doing a foreach.

需要考虑的一件事是,如果您使用延迟执行LINQ语句来生成IEnumerable ,则在从方法返回之前调用.ToList()意味着您的项可能会被迭代两次 - 一次创建List ,一旦调用者循环,过滤或转换您的返回值。在实际应用中,我希望避免将LINQ-to-Objects的结果转换为具体的List或Dictionary,直到我不得不这样做。如果我的调用者需要一个List,那就是一个简单的方法调用 - 我不需要为他们做出这个决定,这使得我的代码在调用者只是做一个foreach的情况下稍微有效。

#6


List<T> offers the calling code many more features, such as modifying the returned object and access by index. So the question boils down to: in your application's specific use case, do you WANT to support such uses (presumably by returning a freshly constructed collection!), for the caller's convenience -- or do you want speed for the simple case when all the caller needs is to loop through the collection and you can safely return a reference to a real underlying collection without fearing this will get it erroneously changed, etc?

List 为调用代码提供了更多功能,例如修改返回的对象和按索引访问。因此,问题可归结为:在您的应用程序的特定用例中,您是否希望支持此类用途(可能是通过返回一个新构建的集合!),以便调用者方便 - 或者您是否希望速度为简单的情况下所有调用者的需求是遍历集合,你可以安全地返回对真实底层集合的引用,而不用担心这会被错误地更改等等?

Only you can answer this question, and only by understanding well what your callers will want to do with the return value, and how important performance is here (how big are the collections you would be copying, how likely is this to be a bottleneck, etc).

只有你能回答这个问题,并且只能理解你的呼叫者想要对返回值做什么,以及这里的性能有多重要(你要复制的集合有多大,这有多大可能成为瓶颈,等等)。

#7


I think you can use either, but each has a use. Basically List is IEnumerable but you have count functionality, add element, remove element

我认为你可以使用其中任何一个,但每个都有用。基本上List是IEnumerable但你有计数功能,添加元素,删除元素

IEnumerable is not efficient for counting elements

IEnumerable对于计算元素效率不高

If the collection is intended to be readonly, or the modification of the collection is controlled by the Parent then returning an IList just for Count is not a good idea.

如果集合只是为了只读,或者集合的修改由Parent控制,那么仅为Count返回IList不是一个好主意。

In Linq, there is a Count() extension method on IEnumerable<T> which inside the CLR will shortcut to .Count if the underlying type is of IList, so performance difference is negligible.

在Linq中,IEnumerable 上有一个Count()扩展方法,如果底层类型是IList,CLR内部将快捷到.Count,因此性能差异可以忽略不计。

Generally I feel (opinion) it is better practice to return IEnumerable where possible, if you need to do additions then add these methods to the parent class, otherwise the consumer is then managing the collection within Model which violates the principles, e.g. manufacturer.Models.Add(model) violates law of demeter. Of course these are just guidelines and not hard and fast rules, but until you have full grasps of applicability, following blindly is better than not following at all.

一般来说,我觉得(意见)更好的做法是在可能的情况下返回IEnumerable,如果你需要做添加,然后将这些方法添加到父类,否则消费者然后在Model中管理违反原则的集合,例如manufacturer.Models.Add(model)违反了demeter法则。当然,这些只是指导方针,而不是硬性规定,但在您完全掌握适用性之前,盲目追求比完全不遵循要好。

public interface IManufacturer 
{
     IEnumerable<Model> Models {get;}
     void AddModel(Model model);
}

(Note: If using nNHibernate you might need to map to private IList using different accessors.)

(注意:如果使用nNHibernate,您可能需要使用不同的访问器映射到私有IList。)

#8


It's not so simple when you are talking about return values instead of input parameters. When it's an input parameter, you know exactly what you need to do. So, if you need to be able to iterate over the collection, you take an IEnumberable whereas if you need to add or remove, you take an IList.

当你谈论返回值而不是输入参数时,这并不是那么简单。当它是输入参数时,您确切地知道您需要做什么。因此,如果您需要能够遍历集合,则需要使用IEnumberable,而如果需要添加或删除,则需要使用IList。

In the case of a return value, it's tougher. What does your caller expect? If you return an IEnumerable, then he will not know a priori that he can make an IList out of it. But, if you return an IList, he will know that he can iterate over it. So, you have to take into account what your caller is going to do with the data. The functionality that your caller needs/expects is what should govern when making the decision on what to return.

在返回值的情况下,它更难。你的来电者期待什么?如果你返回一个IEnumerable,那么他就不会知道他可以从中做出一个IList。但是,如果你返回一个IList,他就会知道他可以迭代它。因此,您必须考虑调用者将对数据执行的操作。调用者需要/期望的功能是在决定返回什么时应该控制的。

#9


as all have said it depends, if you don't want Add/Remove functioanlity at calling layer then i will vote for IEnumerable as it provides only iteration and basic functionality which in design prespective i like. Returning IList my votes are always againist it but it's mainly what you like and what not. in performance terms i think they are more of same.

正如所有人所说,它取决于,如果你不想在调用层添加/删除功能,那么我将投票给IEnumerable,因为它只提供迭代和基本功能,这在设计预期我喜欢。返回IList我的投票总是重新获得,但它主要是你喜欢和不喜欢的。在性能方面,我认为它们更相同。

#10


If you do not counting in your external code it is always better to return IEnumerable, because later you can change your implementation (without external code impact), for example, for yield iterator logic and conserve memory resources (very good language feature by the way).

如果不计算外部代码,最好返回IEnumerable,因为以后可以更改实现(不受外部代码影响),例如,对于yield迭代器逻辑和节省内存资源(顺便提一下非常好的语言特性) )。

However if you need items count, don't forget that there is another layer between IEnumerable and IList - ICollection.

但是,如果您需要项目计数,请不要忘记IEnumerable和IList之间还有另一层 - ICollection。

#11


I might be a bit off here, seeing that no one else suggested it so far, but why don't you return an (I)Collection<T>?

我可能有点偏离这里,看到目前为止没有其他人建议,但为什么不返回(I)Collection ?

From what I remember, Collection<T> was the preferred return type over List<T> because it abstracts away the implementation. They all implement IEnumerable, but that sounds to me a bit too low-level for the job.

根据我的记忆,Collection 是List 的首选返回类型,因为它抽象了实现。它们都实现了IEnumerable,但这对我来说听起来有点太低了。

#12


I think you can use either, but each has a use. Basically List is IEnumerable but you have count functionality, Add element, remove element

我认为你可以使用其中任何一个,但每个都有用。基本上List是IEnumerable但你有计数功能,添加元素,删除元素

IEnumerable is not efficient for counting elements, or getting a specific element in the collection.

IEnumerable对于计算元素或获取集合中的特定元素效率不高。

List is a collection which is ideally suited to finding specific elements, easy to add elements, or remove them.

List是一个非常适合查找特定元素,易于添加元素或删除元素的集合。

Generally I try to use List where possible as this gives me more flexibility.

通常我尽可能使用List,因为这给了我更多的灵活性。

Use List<FooBar> getRecentItems() rather than IList<FooBar> GetRecentItems()

使用List getRecentItems()而不是IList GetRecentItems()

#13


I think the general rule is to use the more specific class to return, to avoid doing unneeded work and give your caller more options.

我认为一般规则是使用更具体的类来返回,以避免做不需要的工作并为调用者提供更多选项。

That said, I think it's more important to consider the code in front of you which you are writing than the code the next guy will write (within reason.) This is because you can make assumptions about the code that already exists.

也就是说,我认为考虑你正在编写的代码比下一个人编写的代码(在合理范围内)更重要。这是因为你可以对已经存在的代码做出假设。

Remember that moving UP to a collection from IEnumerable in an interface will work, moving down to IEnumerable from a collection will break existing code.

请记住,从界面中的IEnumerable向上移动到集合将起作用,从集合向下移动到IEnumerable会破坏现有代码。

If these opinions all seem conflicted, it's because the decision is subjective.

如果这些意见似乎都有冲突,那是因为这个决定是主观的。

#1


It really depends on why you are using that specific interface.

这实际上取决于您使用该特定界面的原因。

For example, IList<T> has several methods that aren't present in IEnumerable<T>:

例如,IList 有几个IEnumerable 中不存在的方法:

  • IndexOf(T item)
  • Insert(int index, T item)
  • Insert(int index,T item)

  • RemoveAt(int index)

and Properties:

  • T this[int index] { get; set; }
  • 这个[int index] {get;组; }

If you need these methods in any way, then by all means return IList<T>.

如果您以任何方式需要这些方法,那么一定要返回IList

Also, if the method that consumes your IEnumerable<T> result is expecting an IList<T>, it will save the CLR from considering any conversions required, thus optimizing the compiled code.

此外,如果使用IEnumerable 结果的方法期望IList ,它将保留CLR不考虑所需的任何转换,从而优化编译的代码。

#2


Framework design guidelines recommend using the class Collection when you need to return a collection that is modifiable by by the caller or ReadOnlyCollection for read only collections.

当您需要返回可由调用者或ReadOnlyCollection为只读集合修改的集合时,框架设计指南建议使用类Collection。

The reason this is preferred to a simple IList is that IList does not inform the caller if its read only or not.

这是一个简单的IList首选的原因是IList不通知调用者它是否只读。

If you return an IEnumerable<T> instead, certain operations may be a little trickier for the caller to perform. Also you no longer will give the caller the flexibility to modify the collection, something that you may or may not want.

如果您返回IEnumerable ,则某些操作可能对调用者来说有点棘手。此外,您不再为调用者提供修改集合的灵活性,这可能是您可能想要或不想要的。

Keep in mind that LINQ contains a few tricks up its sleeve and will optimize certain calls based on the type they are performed on. So, for example, if you perform a Count and the underlying collection is a List it will NOT walk through all the elements.

请记住,LINQ包含一些技巧,并会根据执行的类型优化某些调用。因此,例如,如果您执行Count并且基础集合是List,则它不会遍历所有元素。

Personally, for an ORM I would probably stick with Collection<T> as my return value.

就个人而言,对于ORM,我可能会将Collection 作为我的返回值。

#3


That depends...

Returning the least derived type (IEnumerable) will leave you the most leeway to change the underlying implementation down the track.

返回最少派生类型(IEnumerable)将为您提供最大的余地,以便在轨道上更改底层实现。

Returning a more derived type (IList) provides the users of your API with more operations on the result.

返回更多派生类型(IList)为API的用户提供了对结果的更多操作。

I would always suggest returning the least derived type that has all the operations your users are going to need... so basically, you first have to deremine what operations on the result make sense in the context of the API you are defining.

我总是建议返回最少派生的类型,它包含你的用户将需要的所有操作......所以基本上,你首先必须在你定义的API的上下文中去除对结果的哪些操作有意义。

#4


In general, you should require the most generic and return the most specific thing that you can. So if you have a method that takes a parameter, and you only really need what's available in IEnumerable, then that should be your parameter type. If your method could return either an IList or an IEnumerable, prefer returning IList. This ensures that it is usable by the widest range of consumers.

通常,您应该要求最通用,并返回最具体的内容。因此,如果你有一个带参数的方法,并且你只需要IEnumerable中可用的那个,那么那应该是你的参数类型。如果您的方法可以返回IList或IEnumerable,则更喜欢返回IList。这确保了最广泛的消费者可以使用它。

Be loose in what you require, and explicit in what you provide.

在你需要的东西上松散,并明确你所提供的东西。

#5


One thing to consider is that if you're using a deferred-execution LINQ statement to generate your IEnumerable<T>, calling .ToList() before you return from your method means that your items may be iterated twice - once to create the List, and once when the caller loops through, filters, or transforms your return value. When practical, I like to avoid converting the results of LINQ-to-Objects to a concrete List or Dictionary until I have to. If my caller needs a List, that's a single easy method call away - I don't need to make that decision for them, and that makes my code slightly more efficient in the cases where the caller is just doing a foreach.

需要考虑的一件事是,如果您使用延迟执行LINQ语句来生成IEnumerable ,则在从方法返回之前调用.ToList()意味着您的项可能会被迭代两次 - 一次创建List ,一旦调用者循环,过滤或转换您的返回值。在实际应用中,我希望避免将LINQ-to-Objects的结果转换为具体的List或Dictionary,直到我不得不这样做。如果我的调用者需要一个List,那就是一个简单的方法调用 - 我不需要为他们做出这个决定,这使得我的代码在调用者只是做一个foreach的情况下稍微有效。

#6


List<T> offers the calling code many more features, such as modifying the returned object and access by index. So the question boils down to: in your application's specific use case, do you WANT to support such uses (presumably by returning a freshly constructed collection!), for the caller's convenience -- or do you want speed for the simple case when all the caller needs is to loop through the collection and you can safely return a reference to a real underlying collection without fearing this will get it erroneously changed, etc?

List 为调用代码提供了更多功能,例如修改返回的对象和按索引访问。因此,问题可归结为:在您的应用程序的特定用例中,您是否希望支持此类用途(可能是通过返回一个新构建的集合!),以便调用者方便 - 或者您是否希望速度为简单的情况下所有调用者的需求是遍历集合,你可以安全地返回对真实底层集合的引用,而不用担心这会被错误地更改等等?

Only you can answer this question, and only by understanding well what your callers will want to do with the return value, and how important performance is here (how big are the collections you would be copying, how likely is this to be a bottleneck, etc).

只有你能回答这个问题,并且只能理解你的呼叫者想要对返回值做什么,以及这里的性能有多重要(你要复制的集合有多大,这有多大可能成为瓶颈,等等)。

#7


I think you can use either, but each has a use. Basically List is IEnumerable but you have count functionality, add element, remove element

我认为你可以使用其中任何一个,但每个都有用。基本上List是IEnumerable但你有计数功能,添加元素,删除元素

IEnumerable is not efficient for counting elements

IEnumerable对于计算元素效率不高

If the collection is intended to be readonly, or the modification of the collection is controlled by the Parent then returning an IList just for Count is not a good idea.

如果集合只是为了只读,或者集合的修改由Parent控制,那么仅为Count返回IList不是一个好主意。

In Linq, there is a Count() extension method on IEnumerable<T> which inside the CLR will shortcut to .Count if the underlying type is of IList, so performance difference is negligible.

在Linq中,IEnumerable 上有一个Count()扩展方法,如果底层类型是IList,CLR内部将快捷到.Count,因此性能差异可以忽略不计。

Generally I feel (opinion) it is better practice to return IEnumerable where possible, if you need to do additions then add these methods to the parent class, otherwise the consumer is then managing the collection within Model which violates the principles, e.g. manufacturer.Models.Add(model) violates law of demeter. Of course these are just guidelines and not hard and fast rules, but until you have full grasps of applicability, following blindly is better than not following at all.

一般来说,我觉得(意见)更好的做法是在可能的情况下返回IEnumerable,如果你需要做添加,然后将这些方法添加到父类,否则消费者然后在Model中管理违反原则的集合,例如manufacturer.Models.Add(model)违反了demeter法则。当然,这些只是指导方针,而不是硬性规定,但在您完全掌握适用性之前,盲目追求比完全不遵循要好。

public interface IManufacturer 
{
     IEnumerable<Model> Models {get;}
     void AddModel(Model model);
}

(Note: If using nNHibernate you might need to map to private IList using different accessors.)

(注意:如果使用nNHibernate,您可能需要使用不同的访问器映射到私有IList。)

#8


It's not so simple when you are talking about return values instead of input parameters. When it's an input parameter, you know exactly what you need to do. So, if you need to be able to iterate over the collection, you take an IEnumberable whereas if you need to add or remove, you take an IList.

当你谈论返回值而不是输入参数时,这并不是那么简单。当它是输入参数时,您确切地知道您需要做什么。因此,如果您需要能够遍历集合,则需要使用IEnumberable,而如果需要添加或删除,则需要使用IList。

In the case of a return value, it's tougher. What does your caller expect? If you return an IEnumerable, then he will not know a priori that he can make an IList out of it. But, if you return an IList, he will know that he can iterate over it. So, you have to take into account what your caller is going to do with the data. The functionality that your caller needs/expects is what should govern when making the decision on what to return.

在返回值的情况下,它更难。你的来电者期待什么?如果你返回一个IEnumerable,那么他就不会知道他可以从中做出一个IList。但是,如果你返回一个IList,他就会知道他可以迭代它。因此,您必须考虑调用者将对数据执行的操作。调用者需要/期望的功能是在决定返回什么时应该控制的。

#9


as all have said it depends, if you don't want Add/Remove functioanlity at calling layer then i will vote for IEnumerable as it provides only iteration and basic functionality which in design prespective i like. Returning IList my votes are always againist it but it's mainly what you like and what not. in performance terms i think they are more of same.

正如所有人所说,它取决于,如果你不想在调用层添加/删除功能,那么我将投票给IEnumerable,因为它只提供迭代和基本功能,这在设计预期我喜欢。返回IList我的投票总是重新获得,但它主要是你喜欢和不喜欢的。在性能方面,我认为它们更相同。

#10


If you do not counting in your external code it is always better to return IEnumerable, because later you can change your implementation (without external code impact), for example, for yield iterator logic and conserve memory resources (very good language feature by the way).

如果不计算外部代码,最好返回IEnumerable,因为以后可以更改实现(不受外部代码影响),例如,对于yield迭代器逻辑和节省内存资源(顺便提一下非常好的语言特性) )。

However if you need items count, don't forget that there is another layer between IEnumerable and IList - ICollection.

但是,如果您需要项目计数,请不要忘记IEnumerable和IList之间还有另一层 - ICollection。

#11


I might be a bit off here, seeing that no one else suggested it so far, but why don't you return an (I)Collection<T>?

我可能有点偏离这里,看到目前为止没有其他人建议,但为什么不返回(I)Collection ?

From what I remember, Collection<T> was the preferred return type over List<T> because it abstracts away the implementation. They all implement IEnumerable, but that sounds to me a bit too low-level for the job.

根据我的记忆,Collection 是List 的首选返回类型,因为它抽象了实现。它们都实现了IEnumerable,但这对我来说听起来有点太低了。

#12


I think you can use either, but each has a use. Basically List is IEnumerable but you have count functionality, Add element, remove element

我认为你可以使用其中任何一个,但每个都有用。基本上List是IEnumerable但你有计数功能,添加元素,删除元素

IEnumerable is not efficient for counting elements, or getting a specific element in the collection.

IEnumerable对于计算元素或获取集合中的特定元素效率不高。

List is a collection which is ideally suited to finding specific elements, easy to add elements, or remove them.

List是一个非常适合查找特定元素,易于添加元素或删除元素的集合。

Generally I try to use List where possible as this gives me more flexibility.

通常我尽可能使用List,因为这给了我更多的灵活性。

Use List<FooBar> getRecentItems() rather than IList<FooBar> GetRecentItems()

使用List getRecentItems()而不是IList GetRecentItems()

#13


I think the general rule is to use the more specific class to return, to avoid doing unneeded work and give your caller more options.

我认为一般规则是使用更具体的类来返回,以避免做不需要的工作并为调用者提供更多选项。

That said, I think it's more important to consider the code in front of you which you are writing than the code the next guy will write (within reason.) This is because you can make assumptions about the code that already exists.

也就是说,我认为考虑你正在编写的代码比下一个人编写的代码(在合理范围内)更重要。这是因为你可以对已经存在的代码做出假设。

Remember that moving UP to a collection from IEnumerable in an interface will work, moving down to IEnumerable from a collection will break existing code.

请记住,从界面中的IEnumerable向上移动到集合将起作用,从集合向下移动到IEnumerable会破坏现有代码。

If these opinions all seem conflicted, it's because the decision is subjective.

如果这些意见似乎都有冲突,那是因为这个决定是主观的。