从函数返回多个相同类型的对象时,首选的容器类型是什么?
返回一个简单的数组(比如MyType [])是不是很好的做法,还是应该将它包装在某个通用容器中(比如ICollection< MyType>)?
谢谢!
答案 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>