2009-03-02 135 views
15

从函数返回多个相同类型的对象时,首选的容器类型是什么?我应该从函数中返回一个数组还是一个集合?

返回一个简单的数组(如MyType []),还是应该将它包装在某个通用容器中(如ICollection <MyType>)是否违背了良好习惯?

谢谢!

+0

(最近重复合并的答案) – 2009-06-24 06:26:31

回答

15

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

+0

+1如果你还没有做过,那么你会发布相同的链接。 – 2009-03-02 16:05:54

+0

很棒的发现!我正在阅读它。谢谢! – Pwninstein 2009-03-02 16:27:28

0

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

返回数组的旧风格是泛型之前的拐杖。

3

总是返回一个接口类型,它向调用者提供最多的功能。所以在你的情况下,应该使用ICollection<YourType>

有趣的是,BCL开发人员实际上在.NET框架的某个位置出现了这种错误 - 请参阅该故事的this Eric Lippert blog post

+0

正如他所说,他们没有弄错了,但他们没有作为选件提供泛型(他们是在CLR 2.0中引入)。 – erikkallen 2009-03-02 16:35:58

+0

我知道你在做什么,只能引用这篇文章:“让我给你举个例子,说明我们在框架中以非常明显的方式得到了那个可怕的错误。” :) – 2009-03-02 16:38:40

6

为什么不是List<T>

从其他人所说的埃里克利珀后,我想我会强调这一点:

如果我需要一个序列我会使用 IEnumerable<T>,如果我需要从连续的数字数据我映射 我会 使用List<T>,如果我需要一个映射 横跨任意数据我会使用 Dictionary<K,V>,如果我需要一套我会 使用HashSet<T>。我根本不需要 数组用于任何事情,所以我几乎从不使用 它们。他们没有解决我 比我的 处理中的其他工具更好的问题。

+0

那么它取决于你需要做什么与返回值。 IList 和列表没有相同的可用方法(列表有更多方法可用)。如果你不需要任何这些方法返回IList 无效是更好的解决方案,因为一般的经验法则是返回推断最少限制的类型。然而,使用/参数,局部变量和返回值之间存在很大差异。当你使用一些你知道它是如何使用的,当你返回一些东西时,你不能确定是否使用了返回的 – 2009-06-24 11:04:54

0

什么让你的代码更具可读性,更易于维护,更易于使用。 我会使用简单的数组,更简单==大部分时间更好。 虽然我真的必须看到上下文才能给出正确的答案。

4
return ICollection<type> 

通用返回类型的优点是可以在不更改使用它的代码的情况下更改底层实现。返回特定类型的好处是,您可以使用更多类型特定的方法。

1

为什么不是IList<MyType>

它支持直接索引,这是数组的标志,并且不会消除某天可能返回List<MyType>的可能性。如果你想抑制这个功能,你可能想要返回IEnumerable<MyType>

5

如果正在返回的集合是只读的,这意味着您不希望更改集合中的元素,请使用IEnumerable<T>。这是一个不可变的只读序列(至少从枚举本身来看)元素的最基本表示。

如果您希望它是一个可以更改的自包含集合,请使用ICollection<T>IList<T>

例如,如果您想返回搜索特定文件集的结果,则返回IEnumerable<FileInfo>

但是,如果您想公开目录中的文件,则可能会公开IList/ICollection<FileInfo>,因为您可能想更改集合的内容。

+0

IEnumerabl 不是只读集合。它是序列的一般接口,而且元素是不可变的或不依赖于T的对象是不可变的或不可变的。列表的任何对象都是IEnumerable ,但肯定不会使列表成为只读集合 – 2009-06-24 11:08:51

0

有利于IEnumerable比其他任何东西都有很大的好处,因为这给你最大的实现灵活性,并允许你使用yield return或Linq运算符进行延迟实现。

如果呼叫者想要一个List<T>相反,他们可以简单地调用ToList()上不管你回来了,因为如果你已经创建并从你的方法返回一个新的List<T>整体表现将是大致相同的。

0

阵列有害,但ICollection<T>也有害。

ICollection<T>无法保证该对象将是不可变的。

我的建议是包裹返回的对象与ReadOnlyCollection<T>

8

我会返回一个IList<T>,因为这给您的功能的消费者最大的灵活性。这样,如果你的函数的使用者只需要枚举他们可以这样做的序列,但是如果他们想使用序列作为列表,他们也可以这样做。

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

这是API开发人员可以采用的最不冒风格的方法。这不是由您来决定您的功能的消费者将如何使用他们发送给您的 - 这就是为什么您会在这种情况下返回IList<T>,以便为他们提供最大的灵活性。同样出于同样的原因,你永远不会知道消费者会向你发送什么类型的参数。如果您只需要将发送给您的序列作为参数迭代,则使参数为IEnumerable<T>而不是List<T>


EDIT(一氧化碳):由于它不像的问题将是封闭的,我只是想从另一个问题,添加链接一下:Why arrays are harmful

1

这取决于你打算如何处理你回来的收藏。如果你只是迭代,或者如果你只希望用户迭代,那么我同意@Daniel,返回IEnumerable<T>。如果你真的想要允许基于列表的操作,但是,我会返回IList<T>

5

一块好,我已经听说经常被引用的建议是这样的:

在你接收的慷慨,精确,你提供什么样的。

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

以你的方法的例子,我想如下改写:

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

的关键是,你的内部实现的选择 - 使用列表 - 不透露给调用者,但你返回一个适当的接口。

微软自己的框架开发指导方针建议不要返回特定的类型,以支持接口。 (对不起,我找不到链接)

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

再次以你的实例方法:

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