When to use LINQ's .ToList() or .ToArray()

2019-06-15 09:51发布

问题:

After running this code:

var input = new List<T>( ... );
var result = input.Select( t => new U(t) );

U first1 = null;
foreach ( U u1 in result )
    if ( first1 == null )
        first1 = u1;

U first2 = null;
foreach ( U u2 in result )
    if ( first2 == null )
        first2 = u2;

Then 'first1 == first2' evaluates to false even though both U's wrap the same T. I haven't tested it yet, but I think it can be made to evaluate to true by chaining a .ToList() or .ToArray() onto the Select() call.

In real code, which is much more complex than this simple illustration, what is a good rule of thumb to use for deciding if .ToList() or .ToArray() should be appended? My initial thoughts are either any referenced expression that may be iterated more than once or, to be safer in case potential iterations are not obvious, any referenced expression whose result will never change.

回答1:

Unfortunately, I don't think there is a good "hard and fast" rule here. It depends a lot on how you expect the results to be used, and what the query itself is actually doing.

My initial thoughts are either any expression that may be iterated more than once or, to be safer in case potential iterations are not obvious, any expression whose result will never change.

In general, if you're going to use the result of a query more than once, it's always a good idea to store it via ToList() or ToArray(). This is especially true if you're LINQ query is an "expensive" one, as it prevents the expensive operation from running more than once.

Typically, if you're only going to enumerate the results, then I would leave it as IEnumerable<T>. If you plan to store the results, or use the results more than once, then storing it in a collection can be beneficial.

The other place to watch for is if you return the results in a public API. While it's often nice to return IEnumerable<T>, depending on the expected use case, you may want to consider using ToList() to prevent the operation from being executed more than once.

As for whether to use ToList() or ToArray(), it really depends on how you'll use the results. The cost associated with each is nearly identical (ToList() actually has slightly lower execution overhead if the input is not ICollection<T>). Typically, I prefer ToList() over ToArray() unless I have a specific need or desire for an array.



回答2:

ToList calls List<T>(IEnumerable<T>) constructor to create a List<T>, while ToArrary uses an internal class Buffer<T> to grow the array.

If the source collection (IEnumerable<T>) implements the ICollection interface, the two methods use similar code logic to copy the data.

ICollection.CopyTo(array, 0);  

Otherwise, ToList will creates the List<T> dynamically. While ToArray copies the element one by one into a new array. If the array is full, the method doubles the array size to hold the data. Finally the method returns another array based on the source collection’s size.