0

I'm writing a comparer library of sorts that can accept any type and compares it. Now I'm creating an ordered comparison which could use Comparer<T>.Default.Compare since it does exactly what I want. How would I go about constructing it without knowing the type T at compile-time?

Something like

public static int CompareOrdered<T>(T lhs, T rhs) {
    return Comparer<T>.Default.Compare(lhs, rhs);
}

will not work since T will most often be of type object and I want the most accurate type filled in for T.

What I have now is the following where we assume lhs has the correct comparison type.

    public static int CompareOrdered(object lhs, object rhs) {
        var type = lhs.GetType();
        var comparerType = typeof(Comparer<>).MakeGenericType(type);
        var comparer = comparerType
                         .GetProperty("Default", BindingFlags.Public | BindingFlags.Static)
                         .GetValue(null);
        var func = comparerType
                     .GetMethod("Compare", BindingFlags.Public | BindingFlags.Instance);
        return (int)func.Invoke(comparer, new[] { lhs, rhs });
    }

Which is incredibly ugly. I searched for a general Comparer type where T is not needed, but that does not exist. That would allow for ((Comparer)comparer).Default.Compare(lhs,rhs) which is already a lot better, cleaner and less error-prone way to do this.

So, is there a more proper way to do this?

NetMage
  • 26,163
  • 3
  • 34
  • 55
Didii
  • 1,194
  • 12
  • 36
  • 2
    `Comparer` implements [`IComparer`](https://msdn.microsoft.com/en-us/library/system.collections.icomparer(v=vs.110).aspx). Maybe that helps. – Sebastian Schumann Jul 11 '17 at 08:50
  • That indeed helps. That allows me to already skip the search of `func` which was what I was looking for. I don't think it's possible to skip the search for `Default` so thanks! – Didii Jul 11 '17 at 08:55
  • 2
    Is `Comparer.Default.Compare(lhs, rhs)` an option? That uses [`Comparer`](https://msdn.microsoft.com/en-us/library/system.collections.comparer.compare(v=vs.110).aspx) class without any generics. – Sebastian Schumann Jul 11 '17 at 08:58
  • 1
    Aha, I didn't see `System.Collections.Comparer` because I had another class named `Comparer`. Stupid, stupid. Thanks :) – Didii Jul 11 '17 at 09:04
  • @Verarind If you want, you can answer the question and I'll accept it. – Didii Jul 11 '17 at 11:17
  • I don't care about the reputation. – Sebastian Schumann Jul 11 '17 at 11:20
  • You will probably prefer to stick with the generic implementation you have (i.e. using the marked duplicate). Using non-generic isn't going to solve your concerns about things being "error-prone". As for what's "more proper", that's strictly a matter of opinion (as is "ugly", as in the code you already have). So your question really is also "primarily opinion-based". – Peter Duniho Jul 11 '17 at 21:39
  • 1
    @PeterDuniho I'm not sure that this question is a duplicate to the question you linked. The link points to a question that looks for a how-to call a static mathod. That's not the problem of OP. OP already knows how to do that. I don't think that using the generic version has any benefits. Have a look at the implementation of [`ObjectComparer`](https://referencesource.microsoft.com/#mscorlib/system/collections/generic/comparer.cs,b592983edb9f9aa9) that forwards the call to compare to the ungeneric Comparer-implementation. – Sebastian Schumann Jul 12 '17 at 04:50
  • 1
    @Verarind: `Comparer.Default` only returns `ObjectComparer` when the type doesn't implement `IComparable`. Using `GenericComparer`, which is returned for types that do implement `IComparable`, will be more efficient than using `ObjectComparer`, especially for value types (since the comparison will be possible without boxing). I think the duplicate is appropriate, but I'm not that concerned if it's not a perfect fit, because the other question, "is there a more proper way", is straight-up opinion-based. – Peter Duniho Jul 12 '17 at 05:00

0 Answers0