Syntax for comparing when supporting IComparable

180 Views Asked by At

See code below. There is a squigley red line under first > second Operator cannot be applied to operands OBJ and OBJ.

Is there some easy way to do what is intended here?

public static OBJ Swap<OBJ>(ref OBJ first, ref OBJ second) where OBJ : IComparable
{
    OBJ temp = first;
    OBJ temp2 = second;
    second = temp;
    first = temp2;
    if (first > second) return first else return second;
}
3

There are 3 best solutions below

2
On BEST ANSWER
 if (first.CompareTo(second) > 0) return first else return second;
0
On

If (i > j) works because int supports IComparable.

Nope. This is incorrect. It works because it implements comparison operators. For example:

public static bool operator >(MyClass l, MyClass r) {
    return l.Value > r.Value;
}

This is unrelated to IComparable which requires that a single instance method be defined in implementing classes:

public int CompareTo(object obj) {

It is entirely possible to create a class what implements IComparable without comparison operators, or vice versa.

All you are saying with public static OBJ Swap<OBJ>(ref OBJ first, ref OBJ second) where OBJ : IComparable is that OBJ should implement IComparable - there is nothing implied that the type passed here will have comparison operators defined. Because of this, the compiler can't allow you to perform equality comparisons on objects that may not have comparison operators defined.

I know you're thinking "but the compiler can work out what I've passed at compile time", but remember that your compiled application (even in .exe form) could be referenced by an external application which could pass an invalid type.

You should instead use CompareTo:

return a.CompareTo(b) > 0 ? a : b;
0
On

The reason you're getting that compile-time error is that the only restriction you've placed on the type is that it implements IComparable, the only method that interface guarantees is the CompareTo method, and not all types implement the comparison operators.

Since CompareTo is guaranteed to be available, however, you can use that instead.

Also note that you should use the null conditional operator (?.) when calling the CompareTo method, since there's the possibility that first is null (in which case, calling .CompareTo will throw an ArgumentNullException).

The rest of your code can also be slightly simplified. First, you can shorten it slightly by using the ternary operator (?:) when deciding which item to return. And second, in a swap operation you only need a single temp variable to hold the value of the first variable you re-assign. For example:

public static T Swap<T>(ref T first, ref T second) where T : IComparable
{
    var temp = first;
    first = second;
    second = temp;

    return first?.CompareTo(second) > 0 ? first : second;
}

Here's a case where the null value would otherwise throw an exception, but with the code above it works as expected:

string first = null;
string second = "2";

string largest = Swap(ref first, ref second);