"At least one object must implement IComparable" for an INT? As far as I know, it does

Scott Baker picture Scott Baker · Sep 21, 2012 · Viewed 11.3k times · Source

Ok, I have a simple IEnumerable<HtmlString> things and I want to divide it up into four equal groups.

var quarter = things.OrderBy(t => t.Foo).Count() / 4;

should do the trick, but instead I get this funkiness:

Server Error in '/' Application. At least one object must implement IComparable. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentException: At least one object must implement IComparable.

Line 36: int quarter = things.OrderBy(t => t.Foo).Count() / 4;

Anyone know what the heck is going on here? Why would I need to implement IComparable to get a simple count?

Answer

Jon Skeet picture Jon Skeet · Sep 21, 2012

My guess is that this is to do with lazy evaluation of LINQ's OrderBy. For example, if you have:

var things = unsortedThings.OrderBy(foo => foo.Bar);
var quarter = things.Count() / 4;

then if the foo.Bar properties can't be compared with each other, that will throw exactly that exception.

For example:

using System;
using System.Linq;

class Foo {}

class Program
{
    public static void Main()
    {
        var foos = new[] { new Foo(), new Foo() };
        var ordered = foos.OrderBy(x => x);
        Console.WriteLine(ordered.Count());
    }
}

Output:

Unhandled Exception: System.ArgumentException: At least one object must implement IComparable.
   at System.Collections.Comparer.Compare(Object a, Object b)
   at System.Linq.EnumerableSorter`2.CompareKeys(Int32 index1, Int32 index2)
   at System.Linq.EnumerableSorter`1.QuickSort(Int32[] map, Int32 left, Int32 right)
   at System.Linq.EnumerableSorter`1.Sort(TElement[] elements, Int32 count)
   at System.Linq.OrderedEnumerable`1.<GetEnumerator>d__0.MoveNext()
   at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source)
   at Program.Main()