Обнуляемый универсальный тип, используемый с IComparable. Является ли это возможным? - PullRequest
10 голосов
/ 21 июля 2010

Я пытаюсь создать простой зажим (чтобы я мог связать значения чего-либо сопоставимого ... в основном для числовых типов, таких как int, double и т. Д.)

Проблема в том, что если я сделаю следующее, я получу сообщение об ошибке, но в соответствии с MSDN Считать, что IComparable CompareTo может обрабатывать нулевые значения.
Цитата: «По определению любой объект сравнивается больше нуля, а две нулевые ссылки сравниваются равными друг другу».

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);
    }
}

Ответы [ 2 ]

13 голосов
/ 21 июля 2010

Как сказал @LBushkin Nullable или T?не реализует интерфейс IComparable.Данное решение в порядке, однако я предпочитаю иметь логику сравнения с обнуляемым значением внутри специализированного класса в этом отношении, следуя Принципу единой ответственности , а также использовать его для сравнения любых типов, допускающих Nullable.

Например, вы можете создать универсальный класс сравнения типа Nullable следующим образом:

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);
     }

}

В этом случае вы будете использовать этот класс следующим образом:

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;
}

Удобно для сохраненияв вашей библиотеке помощников.

Надеюсь, это поможет!

7 голосов
/ 21 июля 2010

Помните, Int32? это сокращение от Nullable<Int32>. Поскольку Nullable<T> не реализует IComparable<T>, ваш код, как структурированный, не будет компилироваться.

Однако вы можете перегрузить метод:

public static T? Clamp<T>(this T? value, T? min, T? max) 
    where T : struct, IComparable<T> 
{ 
    // your logic...
} 

Конечно, если вы планируете работать с обнуляемыми типами, вы должны определить, как вы будете фиксировать null значения ...

Если вам на самом деле не нужно фиксировать значения null, может быть проще просто сначала проверить нулевое значение в получателе вашего свойства:

public Int32? Zip
{
   ...
   set
   {
       _zip = value == null ? value : value.Value.Clamp<Int32>(0,99999);
   }

Или, что еще лучше, сделать его частью реализации дополнительной перегрузки для Clamp ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...