Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nullable generic type used with IComparable. Is it possible?

I'm trying to create a simple Clamp (so that I can bound the values of anything comparable ... mostly for number types such as int, double, etc.)

The problem is if I do the following I get an error, but according to MSDN IComparable's CompareTo is supposed to be able to handle null values.
Quote: "By definition, any object compares greater than null, and two null references compare equal to each other."

public static T Clamp<T>(this T value, T min, T max)
    where T : IComparable<T>
{
    if (value.CompareTo(max) > 0)
        return max;

    if (value.CompareTo(min) < 0)
        return min;

    return value;
}



private Int32? _zip;
public Int32? Zip
{
    get
    {
        return _zip;
    }
    set
    {
        _zip = value.Clamp<Int32?>(0, 99999);
    }
}
like image 687
myermian Avatar asked Jul 20 '10 21:07

myermian


1 Answers

As said by @LBushkin Nullable< T > or T? does not implement IComparable interface. The given solution is ok, however I prefer to have the nullable comparing logic inside a specialized class in that matter, following the Single Responsibility Principle, and also than can be used for comparing any Nullable types.

For example, you could create a generic Nullable type comparer class like this:

public class NullableComparer<T> : IComparer<Nullable<T>>
      where T : struct, IComparable<T>
{

     public int Compare(Nullable<T> x, Nullable<T> y)
     {
        //Compare nulls acording MSDN specification

        //Two nulls are equal
        if (!x.HasValue && !y.HasValue)
            return 0;

        //Any object is greater than null
        if (x.HasValue && !y.HasValue) 
            return 1;

        if (y.HasValue && !x.HasValue)
            return -1;

        //Otherwise compare the two values
        return x.Value.CompareTo(y.Value);
     }

}

In this case you would use this class like this:

public static T? Clamp<T>(this T? value, T? min, T? max)
    where T : struct
{
    var comparer = new NullableComparer<T>();

    if (comparer.Compare(value, max) > 0)
        return max;

    if (comparer.Compare(value, min) < 0)
        return min;

    return value;
}

Handy for saving in your helpers library.

Hope it helps!

like image 98
Iñaki Elcoro Avatar answered Sep 28 '22 03:09

Iñaki Elcoro