35

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?

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • You're first creating an empty list, and then attempting to sort that empty list? –  Feb 14 '12 at 22:56
  • 29
    @hvd: Of course not. What I'm doing here is trying to create a simple snippet that demonstrates the issue with as little code as possible. – Jonathan Wood Feb 14 '12 at 22:57
  • 2
    But it doesn't demonstrate the issue, because you've removed so much that it isn't clear whether you've already got a list that you need to sort, or whether you've got an enumerable that you're trying to sort and get into a list. –  Feb 14 '12 at 22:58

6 Answers6

54

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));
phoog
  • 42,068
  • 6
  • 79
  • 117
  • 1
    Thanks, that seems like the most complete answer. I like the idea of using `Sort()` but it isn't quite as convenient because my real data is a class and I want more complicated sorting rules. But I guess I can always create a custom comparer. – Jonathan Wood Feb 14 '12 at 23:06
  • @JonathanWood if the class's ordering is not dependent on the context, you could implement `IComparable` on the class, and `List.Sort()` will use that implementation. – phoog Feb 14 '12 at 23:10
  • 1
    You can also pass a `Comparison` or lambda `(a,b)=>return int` as a sorting function (either inline or by passing a method name), which is sometimes more convenient. (See: http://msdn.microsoft.com/en-us/library/tfakywbh.aspx) – jessehouwing Feb 14 '12 at 23:11
  • @JonathanWood in .NET 4, there's also a `Sort` overload that takes a `Comparison` delegate, so you could still use a lambda expression. – phoog Feb 14 '12 at 23:13
  • 1
    Note from MSDN: List.Sort - this implementation performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal. Enumerable.OrderBy - this method performs a stable sort; that is, if the keys of two elements are equal, the order of the elements is preserved. In contrast, an unstable sort does not preserve the order of elements that have the same key. – Peter Mar 03 '16 at 13:39
  • i got stuck as did not realize System.Linq (name space was not added) so instead it still kind of worked with 'using System.Xml.Linq;' this name space but missing 'OrderBy', the toList() is the part that solves my problem. – visual Apr 13 '18 at 04:39
20

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

items = items.OrderBy(item => item).ToList();
kitti
  • 14,663
  • 31
  • 49
  • Thanks. Does anyone know how efficient `ToList()` is? For example, does it need to allocate a new collection and then copy every item in the list. – Jonathan Wood Feb 14 '12 at 22:56
  • 1
    @JonathanWood Probably. You could use Reflector to find out. If you don't need to preserve the original list, I would go with the `Sort()` option instead. – kitti Feb 14 '12 at 23:00
  • 4
    @JonathanWood yes, it allocates a new list. – phoog Feb 14 '12 at 23:02
  • but why I need to convert? Kindly explain. – Unbreakable Jun 02 '17 at 13:31
  • 1
    @Unbreakable because .OrderBy doesn't return something that is implicitly convertible to List which items is declared as. – Shiv Oct 23 '17 at 16:33
7

You need to use LINQ's ToList() method

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

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

kosa
  • 65,990
  • 13
  • 130
  • 167
6

Try this

items = items.OrderBy(item => item).ToList();
ASetty
  • 114
  • 1
  • 3
4

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();
BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
2

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().

Community
  • 1
  • 1
SRQ Coder
  • 552
  • 5
  • 10