Jonathan Wood
Jonathan Wood

Reputation: 67195

OrderBy and List vs. IOrderedEnumerable

I ran across an unexpected problem with the following code.

List<string> items = new List<string>();
items = items.OrderBy(item => item);

This code generates the error:

Cannot implicitly convert type 'System.Linq.IOrderedEnumerable' to 'System.Collections.Generic.List'. An explicit conversion exists (are you missing a cast?)

It appears I can change items to be of type IEnumerable<string> and the error goes away. But I need to be able to add items to the list, which IEnumerable doesn't support.

Can someone help me understand this error, and what the easiest fix is? Is it safe to simply cast the result?

Upvotes: 35

Views: 61694

Answers (6)

kosa
kosa

Reputation: 66637

You need to use LINQ's ToList() method:

items = items.OrderBy(item => item).ToList();

You can't cast directly from IEnumerable<> to List<>

Upvotes: 7

SRQ Coder
SRQ Coder

Reputation: 552

OrderBy() is an extension method of IEnumerable - and not List.

When the compiler encounters the OrderBy() extension method, it casts the range variable to an IOrderedEnumerable where it can perform the required sorting via CreateOrderedEnumerable method using IComparer et al. Once sorted, the compiler spits out the variable as IEnumerable - usually.

Suggestion: use the var keyword to type 'items' in the LinQ clause.

Certainly the options offered above using the Sort() and ToList() methods will work - however, using them involves greedy operators and you lose the advantage of lazy loading.

Here's a good breakdown here: C# Sort and OrderBy comparison between running Sort() and OrderBy().

Upvotes: 2

phoog
phoog

Reputation: 43046

Why not just sort the list in place using the Sort() instance method; then you can add items to it later if you like:

List<string> items = GetSomeItems();
items.Sort();

Or, use an ordered collection like a binary search tree. SortedSet<T> might fit the bill, depending on your needs.

The solution suggested by the others:

items = items.OrderBy(item => item).ToList(); 

... creates another list with the original items in a new order. This is only useful if you need to preserve the original ordering for some other purpose; it's rather more wasteful of memory than sorting the list in place.

As far as understanding the error, it's simple: List<T> isn't a subtype of IOrderedEnumerable<T>, so there's no implicit reference conversion between the two. The explicit cast that the compiler suggests will satisfy the compiler, but it will fail at run time because the object returned by OrderBy<T> does not inherit from List<T>.

EDIT

An example of List<T>.Sort(Comparison<T>), assuming the type MyType has a Key property of some type type T where T : IComparable<T>:

List<MyType> items = GetSomeItems();
items.Sort((a, b) => a.Key.CompareTo(b.Key));

Upvotes: 54

BrokenGlass
BrokenGlass

Reputation: 160882

For sorting a list of strings you do not need Linq in the first place - just use Sort():

List<string> items = new List<string>();
//add items here
items.Sort();

Upvotes: 4

ASetty
ASetty

Reputation: 114

Try this

items = items.OrderBy(item => item).ToList();

Upvotes: 6

kitti
kitti

Reputation: 14814

You need to convert the IEnumerable to a List. Try this:

items = items.OrderBy(item => item).ToList();

Upvotes: 21

Related Questions