IEnumerable<T> as return type
使用
嗯,我一直被一条规则引导着,"接受你能接受的最少,但返回最大值。"
从这个角度来看,返回
这真是一个由两部分组成的问题。
1)返回IEnumerable是否存在本质上的错误
什么都没有。实际上,如果您使用的是C迭代器,那么这是预期的行为。将其转换为一个列表或另一个集合类不是一个好主意。这样做是对调用方的使用模式进行假设。我觉得对打电话的人做任何假设都不是个好主意。他们可能有充分的理由为什么想要一个IEnumerable。也许他们想将其转换为完全不同的集合层次结构(在这种情况下,到列表的转换是浪费的)。
2)在任何情况下,返回IEnumerable之外的内容是否更可取?
对。虽然这不是一个好主意,假设你的呼叫者,这是完全可以作出决定的基础上,你自己的行为。设想一个场景,您有一个多线程对象,它将请求排队到一个不断更新的对象中。在这种情况下,返回原始的IEnumerable
不过,这肯定是更罕见的情况。
不,在这里返回
调用者可以很容易地将这些数据放入一个列表(或其他任何列表),特别是使用LINQ(
这种方法允许您延迟假脱机返回值,而不必缓冲所有数据。绝对是个好人。前几天我还写了另一个有用的
关于你的原则:"接受你能接受的最少,但返回最大"。
管理大型程序复杂性的关键是一种称为信息隐藏的技术。如果您的方法是通过构建一个
因此,一个更好的原则是让函数遵循:"尽可能少地揭示你是如何工作的"。
IEnumerable对我来说很好,但它有一些缺点。客户端必须枚举才能获得结果。它无法检查计数等。列表是坏的,因为您暴露了太多的控件;客户机可以从中添加/删除等,这可能是一件坏事情。至少在fxcop看来,收藏似乎是最好的组合。我总是使用在我的上下文中看起来合适的方法(例如,如果我想返回只读集合,我将集合公开为返回类型和返回列表.as read only()或IEnumerable,以便通过yield等进行延迟计算)。以个案为基础
"接受你能接受的最少,但回报最多"是我的主张。当一个方法返回一个对象时,有什么理由我们不能返回实际的类型,并且通过返回一个基类型来限制对象的能力。然而,这提出了一个问题:当我们设计接口时,我们如何知道"最大值"(实际类型)是什么?答案很简单。只有在接口设计器正在设计开放接口的极端情况下(该接口将在应用程序/组件外部实现),他们才不知道实际的返回类型可能是什么。智能设计器应该始终考虑方法应该做什么,以及最佳/一般返回类型应该是什么。
例如,如果我正在设计一个接口来检索对象的向量,并且我知道返回对象的计数将是可变的,我总是假设一个聪明的开发人员总是使用一个列表。如果有人计划返回一个数组,我会质疑他的能力,除非他/她只是从他/她不拥有的另一层返回数据。这可能就是fxcop提倡ICollection(列表和数组的公共基础)的原因。
以上所述,还有两件事需要考虑
返回的数据是可变的还是不可变的
如果返回的数据在多个调用方之间共享
关于LINQ懒惰的评估,我确信95%以上的C用户不理解这些无遗嘱。它是如此的不OO-ish。OO促进方法调用的具体状态更改。LinqLazyEvaluation促进表达式评估模式(而不是非高级用户总是遵循的模式)上的运行时状态更改。
一个重要的方面是,当您返回一个
如果只返回一个枚举,那么返回IEnumerable
但正如其他人指出的,如果调用者需要任何其他信息(例如计数),那么他可能需要枚举。如果返回值未实现ICollection,则.NET 3.5扩展方法ienumerable
当结果是一个集合时,我经常返回i list
仅仅因为你说你要返回IEnumerable并不意味着你不能返回一个列表。其目的是减少不必要的耦合。调用者应该关心的只是获取一个事物列表,而不是用于包含该列表的集合的确切类型。如果你有数组支持的东西,那么得到count之类的东西无论如何都会很快。
我不能接受所选的答案。有一些方法可以处理所描述的场景,但使用列表或其他任何方法都不是其中之一。返回IEnumerable时,必须假定调用方可能会执行foreach。在这种情况下,具体的类型是list还是spaghetti并不重要。事实上,仅仅索引是一个问题,特别是如果删除了项。
任何返回的值都是快照。它可能是IEnumerable的当前内容,在这种情况下,如果缓存了它,它应该是缓存副本的克隆;如果它应该更动态(如SQL查询的结果),则使用yield return;但是,允许容器随意变变,并且提供count和indexer等方法会导致多线程中的灾难。世界。我甚至还没有进入调用者调用你的代码应该控制的容器的添加或删除的能力。
同时返回具体的类型会将您锁定到实现中。今天你可能在内部使用一个列表。明天,您可能会成为多线程的,并希望使用线程安全容器、数组、队列、字典的值集合或LINQ查询的输出。如果您将自己锁定到一个具体的返回类型中,那么在返回之前,您必须更改一组代码或进行转换。
我认为你自己的指导是很好的——如果你能够更具体地了解你返回的内容而不影响性能(你不必根据你的结果建立一个列表),那么就这么做。但是,如果您的函数合法地不知道它将找到什么类型,比如在某些情况下,您将使用列表,在某些情况下使用数组等,那么返回IEnumerable是您所能做的"最佳"操作。把它看作是你想要返回的所有事物的"最大公倍数"。