I'm looking for rules of thumb for calling ToList/ToArray/MemoizeAll(Rx)
on IEnumerables
, as opposed to returning the query itself when returning IEnumerable
of something.
Often I find that it is better to just return the query and let the caller decide whether a list is needed or not, but sometimes it can come back and bite you in the rear due to the lazy nature of linq.
I want to collect guidelines such as:
Call ToList if:
- you create new objects (eg. in a select)
- you have side effects in your query
Otherwise, return the query
First off, you should NEVER have side effects in a query. That is a worst practice. Queries should answer a question, not produce an effect.
The answer to your question is: return a query when the caller expects a query; return a list when the caller expects a list. When you design your method, decide what the caller is more likely to want, implement that, and then document it.
When considering whether the caller wants a query or a list, think about the differences between queries and lists:
queries are always up-to-date. If the objects/databases/whatever that the query queries against changes its content, then the query results will change if you run the query again. Lists don't change their contents and therefore lists get out of date. If your caller requires the latest data then give them a query. If they require a snapshot of the data that they can inspect at leisure then give them a list.
queries are potentially expensive to execute to obtain their results. Lists are cheap to obtain their results. If the caller is likely to want to interrogate the result many times and expects to get the same results each time then give them a list.
Constructing a query is fast. Executing a query to construct a list is slow. A list always obtains all the results of a query. The caller might want to further restrict the query, by, say, taking only the first ten elements. If the caller does not want or need to take on the expense of fully iterating over the entire query then give them a query; don't make that decision on their behalf and give them a list.
queries are tiny. Lists are big. Many queries can be iterated over n items in O(1) space; a list with n items takes up O(n) space. If the result set is enormous then putting it in a list is probably inefficient.
and so on.
There is no easy answer. The answer is the same as the answer to any other design problem: Consider all the pros and cons of each possible solution in the context of what is most likely wanted by the user of the feature, and then pick a reasonable compromise solution.
you
ToList()
when you want a list of objects for your result.Return ToList if:
Edit:
Also, return ToList if:
Use
ToList
before you exit theusing
block that holds yourDataContext
.Return a query when the caller is likely/obligated to supply additional filtering criteria which will be used by indexes to reduce # of result rows and/or database IO.
Use ToList if you need to run custom functions on data returned by LINQ to SQL.