Linq .Except function "At least one object must implement IComparable."

Manatherin picture Manatherin · Jan 14, 2011 · Viewed 15.8k times · Source

Basically i have a container which implements IEquatable (sample shown below)

public class ContainerClass  : IEquatable<ContainerClass>
{
        public IEnumerable<CustomClass> CustomClass { get; set; }

        public override bool Equals(object obj) { ... }
        public bool Equals(ContainerClass other) { ... }
        public static bool operator ==(ContainerClass cc1, ContainerClass cc2) { ... }
        public static bool operator !=(ContainerClass cc1, ContainerClass cc2) { ... }
        public override int GetHashCode() { ... }
}

and a CustomClass which also implements IEquatable

public class CustomClass : IEquatable<CustomClass>
{
        public string stringone { get; set; }
        public string stringtwo { get; set; }

        public override bool Equals(object obj) { ... }
        public bool Equals(CustomClass other) { ... }
        public static bool operator ==(CustomClass cc1, CustomClass cc2) { ... }
        public static bool operator !=(CustomClass cc1, CustomClass cc2) { ... }
        public override int GetHashCode() { ... }
}

All this is working fine, so for example, the following works

IEnumerable<CustomClass> customclassone = new List<CustomClass>
    {
        new CustomClass { stringone = "hi" },
        new CustomClass { stringone = "lo" }
    };
IEnumerable<CustomClass> customclasstwo = new List<CustomClass>
    {
        new CustomClass { stringone = "hi" }
    };

var diff = customclassone.Except(customclasstwo);

ContainerClass containerclassone = new ContainerClass 
{
    CustomClass = customclassone.AsEnumerable()
};
ContainerClass containerclasstwo = new ContainerClass 
{
    CustomClass = customclasstwo.AsEnumerable()
};

var diff2 = containerclassone.CustomClass.Except(customclasstwo.CustomClass);

After this code both diff and diff2 when enumerated contain the expected results. However, if i then try

IEnumerable<CustomClass> oldCustom = oldContainerClass.CustomClass;
IEnumerable<CustomClass> newcustom = newContainerClass.CustomClass;
var exceptlist = oldCustom.Except(newcustom);

When i try to enumerate the exceptlist i get "At least one object must implement IComparable.". The only difference between oldCustom and newCustom from the ones in the above working examples is the way they are populated. Anyone got any idea why this is happening?

Answer

Jeff Mercado picture Jeff Mercado · Jan 14, 2011

I suspect that you attempted to sort these contents of the ContainerClass.CustomClass. Due to the deferred execution, you don't know there's a problem until you iterate through it and Except() is just a red herring. CustomClass doesn't implement the IComparable interface so the sort fails with that error. Your CustomClass should either implement the IComparable<T> interface or you should pass in an IComparer on your OrderBy().

e.g.,

oldContainerClass.CustomClass = someListOfSomeType.OrderBy(x => x.CustomClasss, myComparer)
                                                  .Select(x => x.CustomClass);

Though it would help to see what exactly you assigned to these properties so we can give you a more precise reason.