我应该从函数返回一个数组或集合吗?

时间:2022-09-10 23:19:29

What's the preferred container type when returning multiple objects of the same type from a function?

从函数返回多个相同类型的对象时,首选的容器类型是什么?

Is it against good practice to return a simple array (like MyType[]), or should you wrap it in some generic container (like ICollection<MyType>)?

返回一个简单的数组(如MyType [])是不是很好,或者你应该将它包装在一些通用容器中(比如ICollection )?

Thanks!

14 个解决方案

#1


15  

Eric Lippert has a good article on this. In case you can't be bothered to read the entire article, the answer is: return the interface.

Eric Lippert有一篇很好的文章。如果您无法阅读整篇文章,答案是:返回界面。

#2


12  

Return an IEnumerable<T> using a yield return.

使用yield return返回IEnumerable

#3


8  

I would return an IList<T> as that gives the consumer of your function the greatest flexibility. That way if the consumer of your function only needed to enumerate the sequence they can do so, but if they want to use the sequence as a list they can do that as well.

我会返回一个IList ,因为它为您的函数的消费者提供了最大的灵活性。这样,如果您的函数的使用者只需要枚举他们可以这样做的序列,但是如果他们想要将序列用作列表,他们也可以这样做。

My general rule of thumb is to accept the least restrictive type as a parameter and return the richest type I can. This is, of course, a balancing act as you don't want to lock yourself into any particular interface or implementation (but always, always try to use an interface).

我的一般经验法则是接受限制性最小的类型作为参数,并返回最丰富的类型。当然,这是一种平衡行为,因为您不希望将自己锁定到任何特定的接口或实现(但总是尝试使用接口)。

This is the least presumptuous approach that you, the API developer, can take. It is not up to you to decide how a consumer of your function will use what they send you - that is why you would return an IList<T> in this case as to give them the greatest flexibility. Also for this same reason you would never presume to know what type of parameter a consumer will send you. If you only need to iterate a sequence sent to you as a parameter then make the parameter an IEnumerable<T> rather than a List<T>.

这是API开发人员可以采取的最不自负的方法。决定你的函数的消费者将如何使用他们发送给你的东西并不取决于你 - 这就是为什么你会在这种情况下返回IList 以给予他们最大的灵活性。同样出于同样的原因,您永远不会想知道消费者会向您发送什么类型的参数。如果您只需要迭代作为参数发送给您的序列,则将参数设置为IEnumerable 而不是List


EDIT (monoxide): Since it doesn't look like the question is going to be closed, I just want to add a link from the other question about this: Why arrays are harmful

编辑(一氧化碳):因为看起来问题不会被关闭,我只想添加一个关于此问题的链接:为什么数组是有害的

#4


6  

Why not List<T>?

为什么不列出 ?

From the Eric Lippert post mentioned by others, I thought I will highlight this:

从其他人提到的Eric Lippert帖子中,我想我会强调这一点:

If I need a sequence I’ll use IEnumerable<T>, if I need a mapping from contiguous numbers to data I’ll use a List<T>, if I need a mapping across arbitrary data I’ll use a Dictionary<K,V>, if I need a set I’ll use a HashSet<T>. I simply don’t need arrays for anything, so I almost never use them. They don’t solve a problem I have better than the other tools at my disposal.

如果我需要一个序列,我将使用IEnumerable ,如果我需要从连续数字到数据的映射,我将使用List ,如果我需要跨任意数据的映射,我将使用Dictionary ,如果我需要一个集合,我将使用HashSet 。我根本不需要任何数组,所以我几乎从不使用它们。他们没有解决我比其他工具更好的问题。

#5


5  

If the collection that is being returned is read-only, meaning you never want the elements to in the collection to be changed, then use IEnumerable<T>. This is the most basic representation of a read-only sequence of immutable (at least from the perspective of the enumeration itself) elements.

如果要返回的集合是只读的,这意味着您永远不希望更改集合中的元素,那么请使用IEnumerable 。这是不可变的只读序列(至少从枚举本身的角度来看)元素的最基本表示。

If you want it to be a self-contained collection that can be changed, then use ICollection<T> or IList<T>.

如果您希望它是可以更改的自包含集合,请使用ICollection 或IList

For example, if you wanted to return the results of searching for a particular set of files, then return IEnumerable<FileInfo>.

例如,如果要返回搜索特定文件集的结果,则返回IEnumerable

However, if you wanted to expose the files in a directory, however, you would expose IList/ICollection<FileInfo> as it makes sense that you would want to possibly change the contents of the collection.

但是,如果要在目录中公开文件,则会公开IList / ICollection ,因为您可能希望可能更改集合的内容。

#6


5  

A good piece of advice that I've oft heard quoted is this:

我听过的一条很好的建议是:

Be liberal in what you accept, precise in what you provide.

在你接受的内容中要*,在你提供的内容中要准确。

In terms of designing your API, I'd suggest you should be returning an Interface, not a concrete type.

在设计API方面,我建议你应该返回一个接口,而不是一个具体的类型。

Taking your example method, I'd rewrite it as follows:

以您的示例方法为例,我将其重写如下:

public IList<object> Foo() 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

The key is that your internal implementation choice - to use a List - isn't revealed to the caller, but you're returning an appropriate interface.

关键是您的内部实现选择 - 使用List - 不会向调用者显示,但您将返回适当的接口。

Microsoft's own guidelines on framework development recommend against returning specific types, favoring interfaces. (Sorry, I couldn't find a link for this)

Microsoft自己的框架开发指南建议不要返回特定类型,有利于接口。 (对不起,我找不到这个链接)

Similarly, your parameters should be as general as possible - instead of accepting an array, accept an IEnumerable of the appropriate type. This is compatible with arrays as well as lists and other useful types.

同样,您的参数应该尽可能通用 - 而不是接受数组,接受适当类型的IEnumerable。这与数组以及列表和其他有用类型兼容。

Taking your example method again:

再次采用您的示例方法:

public IList<object> Foo(IEnumerable<object> bar) 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

#7


4  

return ICollection<type>

The advantage to generic return types, is that you can change the underlying implementation without changing the code that uses it. The advantage to returning the specific type, is you can use more type specific methods.

泛型返回类型的优点是,您可以更改底层实现,而无需更改使用它的代码。返回特定类型的优点是,您可以使用更多类型特定的方法。

#8


3  

Always return an interface type that presents the greatest amount of functionality to the caller. So in your case ICollection<YourType> ought to be used.

始终返回为调用者提供最大功能的接口类型。所以在你的情况下应该使用ICollection

Something interesting to note is that the BCL developers actually got this wrong in some place of the .NET framework - see this Eric Lippert blog post for that story.

一些有趣的注意的是,BCL开发商实际上得到这个错误在一些地方的.NET Framework - 看到这个埃里克利珀博客帖子这个故事。

#9


1  

Why not IList<MyType>?

为什么不IList ?

It supports direct indexing which is hallmark for an array without removing the possibility to return a List<MyType> some day. If you want to suppress this feature, you probably want to return IEnumerable<MyType>.

它支持直接索引,这是数组的标志,而不会消除某天返回List 的可能性。如果要禁止此功能,可能需要返回IEnumerable

#10


1  

It depends on what you plan to do with the collection you're returning. If you're just iterating, or if you only want the user to iterate, then I agree with @Daniel, return IEnumerable<T>. If you actually want to allow list-based operations, however, I'd return IList<T>.

这取决于您打算如何处理您正在返回的收藏品。如果您只是迭代,或者您只想让用户进行迭代,那么我同意@Daniel,返回IEnumerable 。但是,如果您确实想要允许基于列表的操作,我将返回IList

#11


0  

Use generics. It's easier to interoperate with other collections classes and the type system is more able to help you with potential errors.

使用泛型。与其他集合类进行互操作更容易,类型系统更能够帮助您解决潜在的错误。

The old style of returning an array was a crutch before generics.

返回阵列的旧风格在仿制药之前是一个拐杖。

#12


0  

What ever makes your code more readable, maintainable and easier for YOU. I would have used the simple array, simpler==better most of the time. Although I really have to see the context to give the right answer.

什么使您的代码更易于阅读,可维护且更易于使用。我会使用简单的数组,大多数时候更简单==更好。虽然我真的要看上下文给出正确的答案。

#13


0  

There are big advantages to favouring IEnumerable over anything else, as this gives you the greatest implementation flexibility and allows you to use yield return or Linq operators for lazy implementation.

有利于IEnumerable优于其他任何东西,因为这为您提供了最大的实现灵活性,并允许您使用yield return或Linq运算符进行延迟实现。

If the caller wants a List<T> instead they can simply call ToList() on whatever you returned, and the overall performance will be roughly the same as if you had created and returned a new List<T> from your method.

如果调用者想要一个List ,他们可以简单地在你返回的任何内容上调用ToList(),整体性能将与你创建并从你的方法返回一个新的List 大致相同。

#14


0  

Array is harmful, but ICollection<T> is also harmful.

数组是有害的,但ICollection 也是有害的。

ICollection<T> cannot guarantee the object will be immutable.

ICollection 不能保证对象是不可变的。

My recommendation is to wrap the returning object with ReadOnlyCollection<T>

我的建议是用ReadOnlyCollection 包装返回的对象

#1


15  

Eric Lippert has a good article on this. In case you can't be bothered to read the entire article, the answer is: return the interface.

Eric Lippert有一篇很好的文章。如果您无法阅读整篇文章,答案是:返回界面。

#2


12  

Return an IEnumerable<T> using a yield return.

使用yield return返回IEnumerable

#3


8  

I would return an IList<T> as that gives the consumer of your function the greatest flexibility. That way if the consumer of your function only needed to enumerate the sequence they can do so, but if they want to use the sequence as a list they can do that as well.

我会返回一个IList ,因为它为您的函数的消费者提供了最大的灵活性。这样,如果您的函数的使用者只需要枚举他们可以这样做的序列,但是如果他们想要将序列用作列表,他们也可以这样做。

My general rule of thumb is to accept the least restrictive type as a parameter and return the richest type I can. This is, of course, a balancing act as you don't want to lock yourself into any particular interface or implementation (but always, always try to use an interface).

我的一般经验法则是接受限制性最小的类型作为参数,并返回最丰富的类型。当然,这是一种平衡行为,因为您不希望将自己锁定到任何特定的接口或实现(但总是尝试使用接口)。

This is the least presumptuous approach that you, the API developer, can take. It is not up to you to decide how a consumer of your function will use what they send you - that is why you would return an IList<T> in this case as to give them the greatest flexibility. Also for this same reason you would never presume to know what type of parameter a consumer will send you. If you only need to iterate a sequence sent to you as a parameter then make the parameter an IEnumerable<T> rather than a List<T>.

这是API开发人员可以采取的最不自负的方法。决定你的函数的消费者将如何使用他们发送给你的东西并不取决于你 - 这就是为什么你会在这种情况下返回IList 以给予他们最大的灵活性。同样出于同样的原因,您永远不会想知道消费者会向您发送什么类型的参数。如果您只需要迭代作为参数发送给您的序列,则将参数设置为IEnumerable 而不是List


EDIT (monoxide): Since it doesn't look like the question is going to be closed, I just want to add a link from the other question about this: Why arrays are harmful

编辑(一氧化碳):因为看起来问题不会被关闭,我只想添加一个关于此问题的链接:为什么数组是有害的

#4


6  

Why not List<T>?

为什么不列出 ?

From the Eric Lippert post mentioned by others, I thought I will highlight this:

从其他人提到的Eric Lippert帖子中,我想我会强调这一点:

If I need a sequence I’ll use IEnumerable<T>, if I need a mapping from contiguous numbers to data I’ll use a List<T>, if I need a mapping across arbitrary data I’ll use a Dictionary<K,V>, if I need a set I’ll use a HashSet<T>. I simply don’t need arrays for anything, so I almost never use them. They don’t solve a problem I have better than the other tools at my disposal.

如果我需要一个序列,我将使用IEnumerable ,如果我需要从连续数字到数据的映射,我将使用List ,如果我需要跨任意数据的映射,我将使用Dictionary ,如果我需要一个集合,我将使用HashSet 。我根本不需要任何数组,所以我几乎从不使用它们。他们没有解决我比其他工具更好的问题。

#5


5  

If the collection that is being returned is read-only, meaning you never want the elements to in the collection to be changed, then use IEnumerable<T>. This is the most basic representation of a read-only sequence of immutable (at least from the perspective of the enumeration itself) elements.

如果要返回的集合是只读的,这意味着您永远不希望更改集合中的元素,那么请使用IEnumerable 。这是不可变的只读序列(至少从枚举本身的角度来看)元素的最基本表示。

If you want it to be a self-contained collection that can be changed, then use ICollection<T> or IList<T>.

如果您希望它是可以更改的自包含集合,请使用ICollection 或IList

For example, if you wanted to return the results of searching for a particular set of files, then return IEnumerable<FileInfo>.

例如,如果要返回搜索特定文件集的结果,则返回IEnumerable

However, if you wanted to expose the files in a directory, however, you would expose IList/ICollection<FileInfo> as it makes sense that you would want to possibly change the contents of the collection.

但是,如果要在目录中公开文件,则会公开IList / ICollection ,因为您可能希望可能更改集合的内容。

#6


5  

A good piece of advice that I've oft heard quoted is this:

我听过的一条很好的建议是:

Be liberal in what you accept, precise in what you provide.

在你接受的内容中要*,在你提供的内容中要准确。

In terms of designing your API, I'd suggest you should be returning an Interface, not a concrete type.

在设计API方面,我建议你应该返回一个接口,而不是一个具体的类型。

Taking your example method, I'd rewrite it as follows:

以您的示例方法为例,我将其重写如下:

public IList<object> Foo() 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

The key is that your internal implementation choice - to use a List - isn't revealed to the caller, but you're returning an appropriate interface.

关键是您的内部实现选择 - 使用List - 不会向调用者显示,但您将返回适当的接口。

Microsoft's own guidelines on framework development recommend against returning specific types, favoring interfaces. (Sorry, I couldn't find a link for this)

Microsoft自己的框架开发指南建议不要返回特定类型,有利于接口。 (对不起,我找不到这个链接)

Similarly, your parameters should be as general as possible - instead of accepting an array, accept an IEnumerable of the appropriate type. This is compatible with arrays as well as lists and other useful types.

同样,您的参数应该尽可能通用 - 而不是接受数组,接受适当类型的IEnumerable。这与数组以及列表和其他有用类型兼容。

Taking your example method again:

再次采用您的示例方法:

public IList<object> Foo(IEnumerable<object> bar) 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

#7


4  

return ICollection<type>

The advantage to generic return types, is that you can change the underlying implementation without changing the code that uses it. The advantage to returning the specific type, is you can use more type specific methods.

泛型返回类型的优点是,您可以更改底层实现,而无需更改使用它的代码。返回特定类型的优点是,您可以使用更多类型特定的方法。

#8


3  

Always return an interface type that presents the greatest amount of functionality to the caller. So in your case ICollection<YourType> ought to be used.

始终返回为调用者提供最大功能的接口类型。所以在你的情况下应该使用ICollection

Something interesting to note is that the BCL developers actually got this wrong in some place of the .NET framework - see this Eric Lippert blog post for that story.

一些有趣的注意的是,BCL开发商实际上得到这个错误在一些地方的.NET Framework - 看到这个埃里克利珀博客帖子这个故事。

#9


1  

Why not IList<MyType>?

为什么不IList ?

It supports direct indexing which is hallmark for an array without removing the possibility to return a List<MyType> some day. If you want to suppress this feature, you probably want to return IEnumerable<MyType>.

它支持直接索引,这是数组的标志,而不会消除某天返回List 的可能性。如果要禁止此功能,可能需要返回IEnumerable

#10


1  

It depends on what you plan to do with the collection you're returning. If you're just iterating, or if you only want the user to iterate, then I agree with @Daniel, return IEnumerable<T>. If you actually want to allow list-based operations, however, I'd return IList<T>.

这取决于您打算如何处理您正在返回的收藏品。如果您只是迭代,或者您只想让用户进行迭代,那么我同意@Daniel,返回IEnumerable 。但是,如果您确实想要允许基于列表的操作,我将返回IList

#11


0  

Use generics. It's easier to interoperate with other collections classes and the type system is more able to help you with potential errors.

使用泛型。与其他集合类进行互操作更容易,类型系统更能够帮助您解决潜在的错误。

The old style of returning an array was a crutch before generics.

返回阵列的旧风格在仿制药之前是一个拐杖。

#12


0  

What ever makes your code more readable, maintainable and easier for YOU. I would have used the simple array, simpler==better most of the time. Although I really have to see the context to give the right answer.

什么使您的代码更易于阅读,可维护且更易于使用。我会使用简单的数组,大多数时候更简单==更好。虽然我真的要看上下文给出正确的答案。

#13


0  

There are big advantages to favouring IEnumerable over anything else, as this gives you the greatest implementation flexibility and allows you to use yield return or Linq operators for lazy implementation.

有利于IEnumerable优于其他任何东西,因为这为您提供了最大的实现灵活性,并允许您使用yield return或Linq运算符进行延迟实现。

If the caller wants a List<T> instead they can simply call ToList() on whatever you returned, and the overall performance will be roughly the same as if you had created and returned a new List<T> from your method.

如果调用者想要一个List ,他们可以简单地在你返回的任何内容上调用ToList(),整体性能将与你创建并从你的方法返回一个新的List 大致相同。

#14


0  

Array is harmful, but ICollection<T> is also harmful.

数组是有害的,但ICollection 也是有害的。

ICollection<T> cannot guarantee the object will be immutable.

ICollection 不能保证对象是不可变的。

My recommendation is to wrap the returning object with ReadOnlyCollection<T>

我的建议是用ReadOnlyCollection 包装返回的对象