2

I am trying to figure out the correct way to sort a generic list of objects. A quick example of my data structure:

// The base class
public abstract class Item : IComparable<Item> {
    public enum Category { Hats, Shirts, ... }
    public Category category;

    public int CompareTo (Item that) {
       ...
    }
}

// One of several classes extending Item
public class Hat : Item {
    public int CompareTo (Hat that) {
       ...
    }
}

I have a manager class that maintains lists for each class that extends Item:

Dictionary<Item.Category, List<Item>> _items;

...

foreach (Item.Category category in Enum.GetValues(typeof(Item.Category))) {
    List<Item> list = _items[category];
    list.Sort();
}

The issue I'm having is that when I call List<Item>.Sort(), it's obviously not making use of the class-specific CompareTo() functions. What's the proper way to approach this?

pravprab
  • 2,301
  • 3
  • 26
  • 43
Mike
  • 33
  • 3

2 Answers2

1

The problem is that List<Item>.Sort() is looking for an implementation of IComparable<Item> which your derived class does not implement. You've added a CompareTo(Hat hat) method which has nothing to do with your IComparable<Item> implementation other than they happen to have the same name. You could make CompareTo virtual and overload it, but then you'd have to change the signature of the override:

// The base class
public abstract class Item : IComparable<Item> {
    public enum Category { Hats, Shirts, ... }
    public Category category;

    public virtual int CompareTo (Item that) {
       // default implementation
    }
}

// One of several classes extending Item
public class Hat : Item {
    public override int CompareTo (Item that) {
       // override for Hats - can Hats be compared to other Items?
    }
}

also be very careful that your CompareTo is symmetric and transitive or your sort will fail:

Symmetric : if a < b then b > a

Transitive: If a < b and b < c then a < c

I've seen implementations of CompareTo that aren't transitive and it is tough to diagnose and fix.

You should also take the time to override Equals and the comparison operators

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • Thank you so much, that was exactly the solution I was looking for, but couldn't figure out :). Works perfectly! – Mike May 23 '13 at 03:49
0

is there a reason you can't just use the built in compare that c# comes with ?

list.OrderByDescending(..) or list.OrderBy(..)

if you want to choose to use Icomparable then you have to tell it what to compare ex.

list.Sort((x,y) => x.Category.CompareTo(y.Category));
Scott Selby
  • 9,420
  • 12
  • 57
  • 96
  • Each class has its own sorting logic implemented in CompareTo, so I don't think I can make that work with OrderByDescending/OrderBy. – Mike May 23 '13 at 02:28
  • no you cant , I was just curious , since you didn't post the sorting logic , if it was just generic sort. but it should work when you pass what parameter to sort with lambda like my example – Scott Selby May 23 '13 at 02:29