Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 数据对象属性的最佳实践:IEnumerable vs Array_C#_Ienumerable - Fatal编程技术网

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
强加于所有消费者是一个严重的限制,完全没有必要,除非