函数参数:IEnumerable、ICollection 还是数组?

8
如果我有一个函数,它需要接受某种类型的集合作为参数,那么应该使用什么参数类型? 我之前默认使用 IEnumerable,但我想知道这是否正确,如果正确的话,原因是什么。 由于其名称,ICollection 似乎也是一个合适的选择,但我觉得 IEnumerable 更加用户友好。我认为查看框架提供的示例会是一个好主意,但我发现像 String.Join 这样的函数要求一个字符串数组作为参数。

1
这个问题之前已经在这里得到了回答:https://dev59.com/jnA65IYBdhLWcg3w7DT8最好的问候。 - Oscar
3
String.Join在.NET 4时期添加了一个重载,以便它接受一个IEnumerable。接受数组的重载来自于泛型之前的时代... - Damien_The_Unbeliever
7
@Oscar:那是关于返回类型的问题,我在谈论参数。 - Protector one
你想为参数支持哪些集合类型:栈?队列?字典?数组?还是其他的?你想在参数化函数内部对集合进行只读访问还是读写访问?这些将有助于更好地解释答案并提供更多建议。 - S2S2
@CSharpVJ:那要看情况而定。我是在问一般情况,而不是特定情况。 - Protector one
1
@Protectorone 没问题。我更新了我的回答,展示了通用和具体的建议。特别是,我在回答中提供的博客链接将以更好的方式帮助您。 - S2S2
3个回答

14

你应该选择对客户端最不影响但能完成工作的方式。如果可以使用 IEnumerable<T> 代替 ICollection<T>,那么你应该使用它,因为这样可以给你API的客户端带来更大的灵活性。


同意。但是,在处理作为输入参数传递的IEnumerable对象时,要注意可能出现多次枚举的情况。如果您可以保证方法的使用者始终会提供List、Array或Collection中的一个,则可以使用ICollection<T>代替。否则,您需要枚举整个枚举(例如,转换为ToList()),然后再使用枚举对象。 - Lesair Valmont

4

在IT技术中,IEnumerable比ICollections更受欢迎。您可以在这里看到有关您问题的详细解答。


3

接口主要用作函数的参数或返回类型,以支持“SOLID”设计原则中的“接口隔离原则(Interface Segregation Principle)”,使强制转换更容易,支持将多个具体类型传递给接口参数,并从公共函数的客户端隐藏(封装)实际参数类型。

  • 关于“IEnumerable”:

非常基础,它公开了枚举器,支持对非泛型集合进行简单迭代。

[ComVisibleAttribute(true)]    
public interface IEnumerable
  • 下面是关于ICollection的内容:

ICollection接口扩展了IEnumerable接口;IDictionaryIList是更专业化的接口,它们都扩展了ICollection接口。一个IDictionary实现是一组键/值对,就像Hashtable类一样。一个IList实现是一组值,并且它的成员可以通过索引访问,就像ArrayList类一样。 一些限制元素访问的集合,如Queue类和Stack类,直接实现ICollection接口。 如果既不需要IDictionary接口,也不需要IList接口来满足所需集合的要求,则从ICollection接口派生新的集合类以获得更大的灵活性。

[ComVisibleAttribute(true)]
public interface ICollection : IEnumerable

以下是关于IList接口的信息:

[ComVisibleAttribute(true)] public interface IList : ICollection, IEnumerable

MSDN中有更多关于IList的内容: IListICollection接口和所有非泛型列表的基本接口。IList实现分为三类:只读、固定大小和可变大小。只读IList不能被修改。固定大小IList不允许添加或删除元素,但允许修改现有元素。可变大小IList允许添加、删除和修改元素。
提示: 如果你只希望为集合参数支持foreach语句,IEnumerable就足够了。如果你还希望支持向集合中添加和删除元素,IList则是更好的选择。
建议: 这篇博客文章:IEnumerable, ICollection, IList Compared一定会帮助你做出更好和精确的决策。 此外,查看该文章可以了解IList和IEnumerable的性能和其他比较。

3
我完全不同意。在实现工作的最小抽象层面上(在特定情况下),你应该始终使用最少的抽象,这样你所编写的客户端代码就不会受到限制,函数变得更加通用并且具有更大的重用潜力。 - Binary Worrier
嗯,@BinaryWorrier,我更新了答案,使用IList仅在需要支持添加或删除项时才是选择,而如果只需要foreach支持,则使用IEnumerable。希望你现在更好地理解了答案。 - S2S2
1
抱歉,我仍然不同意。应该优先选择IEnumerable<T>,因为它是最小的抽象层。例如,假设您有一个函数,它接受一组数字并获取最小值、最大值和平均值。如果该函数采用ICollection,则可以被实现ICollection接口的任何类使用。如果编写为采用IEnumerable,则可以在_任何东西_上工作,因为您可以轻松编写适配器,用于DataReaders或文件读取器,而不会导致额外的存储或处理开销,并且仍然使用相同的函数。 - Binary Worrier
@BinaryWorrier,尽管您不同意我的答案,但我完全同意您的评论。如果原始“问题”清楚地提示了所需集合参数的只读使用或读写使用,那么答案将更加具体和直接... - S2S2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接