0

I think my code is self explanatory about what i want to achieve :

private bool Comparison<T>(T operatorOne, T operatorTwo, string operand)
    {
        switch (operand.ToLower())
        {
            case "=":
                return operatorOne.Equals(operatorTwo);
            case "<":
                return operatorOne < operatorTwo;
            case ">":
                return operatorOne > operatorTwo;
            case "contains":
                return operatorOne.ToString().Contains(operatorTwo.ToString());
            default:
                return false;
        }
    }

It gives me error :

Error   16  Operator '>','<' cannot be applied to operands of type 'T' and 'T'

I need a method that can compare strings, Int,Double, chars. Note: Exclude the condition that strings will be passed for > or < check OR Int will be sent for "contains" check

isumit
  • 2,313
  • 4
  • 23
  • 28

1 Answers1

11

You could use Comparer<T>.Default.Compare(operatorOne, operatorTwo) for comparation. Please be aware that if T does not implement IComparable and IComparable<T>, Comparer<T>.Default.Compare throws an exception.

To make sure that T implements IComparable, you may add where T: IComparable constraint. (It will exclude classes which implement IComparable<T>, but not IComparable. Still may be acceptable, since many classes which implement IComparable<T>, implement IComparable too.)

private bool Comparison<T>(T operatorOne, T operatorTwo, string operand)
    where T: IComparable
{
    switch(operand.ToLower())
    {
        case "=":
            return Comparer<T>.Default.Compare(operatorOne, operatorTwo) == 0;
        case "<":
            return Comparer<T>.Default.Compare(operatorOne, operatorTwo) < 0;
        case ">":
            return Comparer<T>.Default.Compare(operatorOne, operatorTwo) > 0;
        case "contains":
            return operatorOne.ToString().Contains(operatorTwo.ToString());
        default:
            return false;
    }
}

P.S.

As Servy suggested, you may also pass IComparer as an extra parameter to the function. It would allow to cover types which implement neither IComparable nor IComparable<T>, so Comparer<T>.Default does not work for them.

Also, credits go to @TimothyShields, who suggested Comparer<T>.Default.

Servy
  • 202,030
  • 26
  • 332
  • 449
AlexD
  • 32,156
  • 3
  • 71
  • 65
  • 1
    @isumit With Comparer.Default you could even remove `where` constraint. – AlexD Aug 22 '14 at 15:25
  • 1
    @AlexD You *can* but you *shouldn't*, unless you accept an `IComparer` as a parameter. The given code will fail at runtime if the type doesn't implement `IComparable`; with the generic constraint the code will fail at compile time if an unsuitable type is used. – Servy Aug 22 '14 at 15:54
  • @Servy I was just editing the answer. A slight problem here is that `Comparer.Default.Compare` may return either `IComparable` or `IComparable`, which is hard to express via `where` constraint. We can say `where IComparable` since classes which implement `IComparable` usually implement `IComparable` too. But it still opens a corner case where only `IComparable` is implemented. – AlexD Aug 22 '14 at 16:05
  • @AlexD That's why I always accept the comparer as a parameter, rather than expecting the default comparer to be implemented. You see the BCL do the same thing. This allows types that don't implement either interface to be used. – Servy Aug 22 '14 at 16:07
  • @Servy Do you mean to have the comparer as an extra parameter of `Comparison` function? Sure, such comparer can compare whatsoever, but it would change the function signature. – AlexD Aug 22 '14 at 16:15
  • @AlexD I'd go with an `IComparer`, not a delegate, but the idea is the same. You could have both overloads if you wanted. Yes, it would change the function signature; my whole assertion is that doing so would improve the function. – Servy Aug 22 '14 at 16:24