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

时间:2009-03-02 16:00:11

标签: c# .net return-type

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

返回一个简单的数组(比如MyType [])是不是很好的做法,还是应该将它包装在某个通用容器中(比如ICollection< MyType>)?

谢谢!

14 个答案:

答案 0 :(得分:16)

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

答案 1 :(得分:13)

使用yield return返回IEnumerable<T>

答案 2 :(得分:8)

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

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

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


编辑(一氧化碳):由于看起来问题不会被关闭,我只想添加其他问题的链接:Why arrays are harmful < / p>

答案 3 :(得分:6)

为什么不List<T>

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

  

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

答案 4 :(得分:5)

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

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

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

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

答案 5 :(得分:5)

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

  

在你接受的内容中保持自由,在你所提供的内容中保持准确。

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

采用您的示例方法,我将其重写如下:

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

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

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

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

再次采用您的示例方法:

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

答案 6 :(得分:4)

return ICollection<type>

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

答案 7 :(得分:3)

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

有趣的是,BCL开发人员实际上在.NET框架的某个地方出错了 - 请参阅this Eric Lippert blog post了解该故事。

答案 8 :(得分:1)

为什么不IList<MyType>

它支持直接索引,这是数组的标志,但不会删除某天返回List<MyType>的可能性。如果要取消此功能,可能需要返回IEnumerable<MyType>

答案 9 :(得分:1)

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

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

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

答案 12 :(得分:0)

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

如果来电者想要一个List<T>,他们只需在您返回的内容上调用ToList(),整体效果将与您创建并返回新{{1}时大致相同从你的方法。

答案 13 :(得分:0)

数组有害,但ICollection<T>也有害。

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

我的建议是用ReadOnlyCollection<T>

包装返回的对象