简短问题:将数据对象属性声明为IEnumerable
是否可以,或者它应该是Array
?
背景
我刚刚在项目中发现了一个导致性能问题的错误。原因是IEnumerable已被多次迭代。但这只是初看起来很简单。我认为那里存在一个设计缺陷,允许这种情况发生。
更深入的调查显示,一个方法GetAllUsers
返回了一个UsersResponse
对象,其中一个属性为IEnumerable<T> UsersList
。实现缓存时,显然整个UsersResponse
对象都被缓存,并且当时工作正常,因为GetAllUsers
已将数组分配给IEnumerable<T> UsersList
。后来GetAllUsers
的实施发生了变化,由于某些原因,开发人员认为ToArray()
调用是多余的。所以我认为问题在于UsersResponse
对象没有经过精心设计,并且为它的工厂方法提供了太多的自由。另一方面,缓存包含IEnumerable
属性的对象原则上也是无用的。
所以我们回到我的一般设计数据对象的问题:当你声明它时,不知道它将来会被缓存,或者除了当前的需要以外它将如何以其他方式使用,是吗?可以将其属性声明为IEnumerable
,将谨慎使用的责任放在其他开发人员身上,或者从一开始就必须Array
?
我搜索过的内容:
我发现的唯一建议是Jon Wagner's blog post,他建议在建立后立即“密封”LINQ链。但这与构建IEnumerable相关,而不是将其存储在实体属性中。虽然结合原则尽可能返回特定类型,但它可能意味着将属性声明为Array
。
答案 0 :(得分:1)
当我考虑API设计时,我总是试图对消费者“好”。这意味着尽可能多地接受参数(如果可能),并尽可能多地提供返回值。如果你也购买了它,这意味着你应该在提供IEnumerable
(或类似的)返回值的同时争取Array
个参数。结果是API消费者的最大价值(即使最终是你自己)。
答案 1 :(得分:0)
我通常赞成Array
方法,除非它被强制进入集合。
特别是当有很多数值计算时。
优点:
最后但并非最不重要的是,坚持一个,绝不使用两者。将一个集合从Array转换为Collection是很糟糕的,反之亦然,这也没有用。
答案 2 :(得分:0)
应该使用满足要求的最抽象类型。如果您需要在DTO中存储“打开”查询,则使用ICollection<T>
或(如果您需要索引访问权限)IList<T>
来获取该属性。
使用array
将指导您进行具体实施。这可能不是问题,或者可能在以后的某个时候变成痛苦。后者排除了array
恕我直言。
顺便说一句:调用者有责任只在IEnumerable<T>
上进行一次迭代。