C# 数据对象属性的最佳实践:IEnumerable vs Array
简短问题:可以将数据对象属性声明为C# 数据对象属性的最佳实践:IEnumerable vs Array,c#,ienumerable,C#,Ienumerable,简短问题:可以将数据对象属性声明为IEnumerable,还是应该声明为数组 背景: 我刚刚在我们的项目中发现了一个导致性能问题的bug。原因是IEnumerable已被多次迭代。但这只是一见钟情。我认为这是一个设计缺陷导致的 更深入的研究表明,一个方法GetAllUsers返回了一个UsersResponse对象,其属性之一是IEnumerable UsersList。在实现缓存时,显然整个UsersResponse对象都在缓存中,而且当时运行良好,因为GetAllUsers为IEnumera
IEnumerable
,还是应该声明为数组
背景:
我刚刚在我们的项目中发现了一个导致性能问题的bug。原因是IEnumerable已被多次迭代。但这只是一见钟情。我认为这是一个设计缺陷导致的
更深入的研究表明,一个方法GetAllUsers
返回了一个UsersResponse
对象,其属性之一是IEnumerable UsersList
。在实现缓存时,显然整个UsersResponse
对象都在缓存中,而且当时运行良好,因为GetAllUsers
为IEnumerable UsersList
分配了一个数组。后来的GetAllUsers
实现发生了变化,出于某种原因,开发人员决定ToArray()
调用是多余的。所以我认为问题在于,UsersResponse
对象设计得不好,它的工厂方法允许太多的自由度。另一方面,缓存包含IEnumerable
属性的对象原则上也是无用的
因此,我们回到我的一般设计数据对象的问题:当您声明它时,不知道它是否会在将来某个时候被缓存,或者除了您当前的需要之外它将如何以其他方式使用,是否可以将它的属性声明为IEnumerable
,将谨慎使用的责任交给其他开发人员,或者从一开始就必须是Array
我搜索的内容:
我发现的唯一建议是,他建议在LINQ链建成后立即“密封”它们。但这更多地涉及到构建IEnumerable,而不是将其存储在实体属性中。尽管与原则结合,尽可能返回特定的类型,但这可能意味着将属性声明为
数组
我通常支持数组
方法,除非强制将其放入集合中。
特别是当有很多数值计算的时候
优点:
- 紧凑型存储。(黑客技术的概率)
- []存取器。(不适用于C#)
- 多维数组的可读代码
最后但并非最不重要的一点是,坚持使用其中一种方法,不要同时使用这两种方法。将一个集合从一个数组转换到另一个集合是很糟糕的,反之亦然,这也没有什么好处。当我考虑API设计时,我总是试图对消费者“友好”。这意味着接受尽可能多的参数(如果可能),并提供尽可能多的返回值。如果您也这么认为,这意味着您应该在提供
Array
(或类似)返回值的同时,努力获得IEnumerable
参数。结果是API的使用者获得了最大的价值(即使最终是你自己)。应该使用满足要求的最抽象的类型。如果需要使“打开的”查询无法存储在DTO中,则对属性使用ICollection
或(如果需要索引访问)IList
使用数组
将确定具体的实现。这可能不是问题,也可能在以后某个时候成为一种痛苦。后者排除了array
IMHO
顺便说一句:调用方有责任只在
IEnumerable
上迭代一次,答案是:这取决于。在一种情况下,您可能希望在另一种情况下使用前向只读集合-数组。并没有适合所有人的最佳方法。@oleksii,请您稍微扩展一下:在哪种情况下,您会在数据实体中使用仅向前的收集?我也认为答案应该是“视情况而定”,但找不到任何合理的案例。我记得在这个话题上有过一些广泛的辩论。对不起,请看和@oleksii,但这两个答案都不能回答我的问题。在开始新的线程之前,我已经看到了其中的一些线程。它们都过于笼统,答案显然是“视情况而定”。我的问题专门针对数据对象。类似于从数据库存储库、web服务或内部构建实体返回的,用于将数据从一个类传递到另一个类。这里的核心是数据对象原则上应该表示数据,而不是如何检索数据的操作。同样的问题也适用于Lazy和数据实体中的委托。@oleksii,缓存只是使用IEnumerable引起的问题的一个例子。当您设计一个数据实体时,您通常不知道它将如何在未来的每个场景中使用,这就是问题所在——您必须根据使用情况的假设来决定IEnumerable或Array。支持数组的另一点是,将来可以将其更改为IEnumerable,而不会破坏向后兼容性(只是更改行为)。在Array下,我的意思是T[],所以LINQ在它上面工作得很好。我问题中的数据实体既可以用作一组方法的返回参数,也可以用作其他方法的参数。这种情况如何?我同意,在参数中使用IEnumerable,但始终返回列表或T[]作为返回类型。唯一令人恼火的是,你不能使用yield-return代码>:(返回T[]
或List
会暴露您的实现,这是一个大难题。@demoncodemonkey有时我也想使用yield return
。然后我只想破例:-)@OleksandrPshenychnyy在我看来,Array
更适合您的情况,因为您需要缓存东西。此外,与您的团队讨论课堂设计。将IEnumerable
强加于所有消费者是一个严重的限制,完全没有必要,除非