我正在寻找在IEnumerables上调用ToList / ToArray / MemoizeAll(Rx)的经验法则,而不是在返回IEnumerable时返回查询本身.
通常我发现最好只是返回查询,让调用者决定是否需要一个列表,但是有时候它可以回来,因为linq的懒惰性质而在后面咬你.
我想收集如下指导:
Call ToList if:
- you create new objects (eg. in a select)
- you have side effects in your query
Otherwise,return the query
解决方法
首先,你不应该在查询中有副作用.这是最糟糕的做法.查询应该回答一个问题,不产生影响.
您的问题的答案是:当调用者期望查询时返回查询;当调用者期望列表时返回一个列表.当您设计方法时,请确定调用者更有可能需要什么,实现该方法,然后记录它.
在考虑调用者是否要查询或列表时,请考虑查询和列表之间的差异:
>查询始终是最新的.如果对象/数据库/查询查询的任何内容都会更改其内容,那么如果再次运行查询,查询结果将会更改.列表不更改其内容,因此列表过期.如果您的呼叫者需要最新的数据,那么请给他们一个查询.如果他们需要他们可以随时检查的数据的快照,那么给他们一个清单.
>查询执行成本可能很高,以获得结果.列表便宜以获得结果.如果呼叫者可能想要多次询问结果,并希望每次得到相同的结果,然后给他们一个列表.
>构造查询很快.执行查询来构造列表很慢.列表总是获取查询的所有结果.调用者可能想要进一步限制查询,比如说只取前十个元素.如果调用者不想要或需要花费在整个查询上完全迭代的费用,那么给他们一个查询;不要代表他们作出决定,并给他们一个清单.
查询很小名单大可以在O(1)空间中的n个项目上迭代许多查询;具有n个项目的列表占用O(n)空间.如果结果集是巨大的,那么将其放在列表中可能是低效的.
>等等.
没有简单的答案.答案与任何其他设计问题的答案相同:在功能的用户最有可能希望的范围内考虑每个可能解决方案的所有优缺点,然后选择合理的折衷解决方案.