问题 最佳类型设置为返回集合的方法的返回类型?


返回收藏品的最佳类型是哪种?

我应该用吗? IList<T>IEnumerable<T>IQueryable<T>还有什么?哪个是最好的 为什么

我正在尝试决定我应该使用哪种方式,无论是在接口还是我正在编写的几个类的实现中。

编辑 让我更进一步说明这一点,我使用LINQ to SQL通过WCF服务返回数据。感觉这可能会改变最佳使用类型?


2277
2017-10-20 18:45


起源

这里有一个很好的讨论: stackoverflow.com/questions/1456132/...。 - Jeff Sternal
根据上面的评论,当使用'IEnumerable <T>'时,我班级的消费者如何使用它?刚解释回“List <T>”? - Nate
不,这样的演员会违反界面,并且可能在某些时候失败。使用者应该使用返回的确切接口或其父级。因此,例如,如果它返回IList <T>并且你需要的只是IEnumerable <T>的功能,那么你应该使用它。 - Steven Sudit
消费者如何使用它?如果方法返回IEnumerable <T>,消费者如何调用该方法并存储结果?具体的泛型类型使用IEnumerable? - Nate
@Nate - 您可以将其存储为IEnumerable <T>。拥有IEnumerable <T>类型的字段或属性是完全没问题的。感谢LINQ,您可以使用IEnumerable <T>做很多事情。您可以通过索引,排序,查找(通过Where)等进行访问.List <T>,HashSet <T>和LinkedList <T>是IEnumerable <T>的一些具体实现。 - Mike Two


答案:


我默认为IEnumerable。我正在拍摄最小的界面曝光。都 IList<T> 和 IQueryable<T> 实行 IEnumerable<T>。因此,除非您对方法有其他特定要求,否则我会选择极简主义并使用最少派生类型。如果您的调用代码中有其他要求,例如索引查找的性能或获取集合中的项目数,那么您可能希望选择其他类型,例如 ICollection<T>


1
2017-10-20 18:51



IEnumerable <T>是有意义的,如果你确定你想要支持的唯一场景是仅向前迭代。 - Justin R.
@ fatcat1111 - 你是对的,但如果我要回收一个集合,这通常是我想要支持的唯一场景。如果我想修改集合或做其他事情,那么我将为此提供描述性方法。我不会返回IList <Employee>,所以有人可以调用Add。我将有一个AddEmployee方法。 - Mike Two
这正是我的想法。这支持使用WCF或其他基于服务的体系结构。 - Nate
@Mike Two:我同意将List <T>作为IList <T>返回会将其暴露给不需要的更改,但是返回List <T> .AsReadOnly()呢?这使您可以获取Count,按索引访问成员等。 - Steven Sudit
@Nate - 更像 IEnumerable<T> result = obj.ReturnIEnumerable(); 您可以拥有声明为接口类型的变量。它实际上允许您更灵活地编写 ReturnIEnumerable()它可以返回List <T>或HashSet <T>或LinkedList <T>,或者它可能正在执行 yield return ... 您的来电者永远不需要知道。如果IEnumerable <T>的契约足够,并且由于LINQ经常是这样,那么将它保留为IEnumerable <T>。 - Mike Two


框架设计指南 州:

使用 Collection<T> 或者是。的子类    Collection<T> 属性或返回   表示读/写的值   集合。

public Collection<Session> Sessions { get; }

使用 ReadOnlyCollection<T>,一个子类   的 ReadOnlyCollection<T>或者很少见   例 IEnumerable<T> 对于属性或   返回表示只读的值   集合。

public ReadOnlyCollection<Session> Sessions { get; }

一般来说,更喜欢    ReadOnlyCollection<T>

关于LINQ,为.NET 3.5创建的指南是明确的,但不是(imo)完全令人信服的理由:

审查机构明确表示   LINQ的决定   不应该改变这个指导方针   [“不要回来 IEnumerator<T>,   除了作为a的返回类型    GetEnumerator 方法“]。你的   来电者最终会笨手笨脚   对象模型,如果他们选择不使用   LINQ或没有的语言   支持它。


5
2017-10-20 18:53



那些是.NET 3.5之前的准则吗?想知道LINQ是否让我向IEnumerable <T>漂移。 - Mike Two
懒惰的eval + LINQ让我更多地考虑IEnumerable <T> - Matthew Whited
使用'IEnumerable <T>时,我班的消费者如何使用它?刚解释回“List <T>”? - Nate
非常有趣 - 我想知道为什么ReadOnlyCollection在只读情况下优于IEnumerable? - Mathias
这本书已经有一年了......我倾向于倾向于IList <T>或IEnumerable <T> - Chuck Conway


使用所有可能的返回类型将符合的最不一般的类型。即,如果您正在查看的方法可能会返回 List<int> 或者 int[],然后我输入为 IEnumerable<int> ......如果它可以返回 List<int> 或者a List<Employee> 或者 int[] 我输入为 IEnumerable。如果它总是返回a Collection<Employee> 或者a Collection<SalariedEmployee> 然后回来 Collection<Employee> 

如果该方法将始终生成相同的类型,请使用该类型...

在消耗方法或接口中,otoh,返回的对象所在的位置 用过的,你应该使用相反的哲学,输入传入的方法参数作为 至少一般 消费方法中代码的内部功能所需的类型...即,如果使用集合对象的所有方法都通过它进行枚举 foreach,那么传入的参数类型应该 IEnumerable<> 


5
2017-10-20 18:50





如果集合是无序的或不需要随机访问,则IEnumerable是正确的。如果它是一个列表并且您希望将其公开为一个列表,则声明方法或属性以返回IList,但您可能需要在该集合上返回一个ReadOnlyCollection包装器(直接或使用诸如List.AsReadOnly()之类的语法) 。只有当我有一些有用的覆盖时,我才会返回IQueryable。


2
2017-10-20 18:57





写作时 应用,我没有看到返回特定泛型类型的任何问题,例如:

List<myType> MyMethod()
{
  ...
}

根据我的经验,对于原始开发人员来说这很容易,并且其他开发人员也很容易理解原始开发人员的意图。

但是,如果您正在开发某种将被其他开发人员使用的框架,您可能希望更复杂 - 例如,返回一个接口。


0
2017-10-20 19:06



这种方法的主要问题是当类更新为使用List <T>之外的其他东西时,接口会中断。小问题是暴露整个List <T>允许通过插入或删除进行修改。 - Steven Sudit
你是对的,但这是我的经验(至少在应用程序开发中),改变类返回的集合类型是相当罕见的。我宁愿稍后支付重构的罚款 - 只要需要,而不是过度设计我的所有收集界面。你的经历可能会有所不同,当然...... - Tom Bushell
我确实理解你对应用程序的重视程度,但我认为即使你没有编写可重用的组件,返回界面的灵活性也很有价值,特别是当应用程序必须进行维护和调整时。 - Steven Sudit


它最终取决于您要对返回的数据执行的操作。请记住,IEnumerable意味着(通过我的意思是强制)您以顺序方式访问数据。您无法添加,更改它,也无法访问阵列中特定点的项目。

IList没有此问题,但您必须提供其他功能来实现它。如果从.net对象继承,您可能不必担心它,但它实际上取决于您创建对象的方式。

每个都有他们的权衡,没有人总是默认。


0
2017-10-20 18:56



在返回之前,您不必收集所有数据 IList。事实上,我经常使用 IList 当我想提供随机访问和a Count 财产,但不想花时间预先收集数据。例如,消费者可能只想要第5个元素,因此您不希望对数据库进行五次调用以填充项目0-4(以使用您的示例)。它很容易写出来 IList 按需填充自己的实现。 - P Daddy
我没想到,但你是对的。 - kemiller2002