2010-07-20 14 views
9

Próbuję utworzyć prosty zacisk (tak, żebym mógł powiązać wartości z czymkolwiek porównywalnym ... głównie dla typów liczbowych, takich jak int, double itp.).Nullable rodzajowy używany z IComparable. Czy to możliwe?

Problem polega na tym, że wykonuję następujące czynności Wystąpił błąd, ale porównanie z funkcją IComparable ma być w stanie obsłużyć wartości null.
Cytat: "Z definicji każdy obiekt porównuje wartość większą niż zero, a dwie wartości zerowe są równe sobie."

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

Odpowiedz

7

Pamiętaj, Int32? jest skrótem Nullable<Int32>. Ponieważ Nullable<T> nie implementuje IComparable<T>, Twój kod, zgodnie ze strukturą, nie będzie się kompilować.

Można jednak przeciążyć metodę:

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

oczywiście, jeśli masz zamiar pracować z pustych typów, trzeba określić, jak będzie zacisnąć null wartości ...

Jeśli nie faktycznie trzeba zacisnąć null wartości, może być prostsze tylko najpierw sprawdzić dla wartości null w getter własności:

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

Albo jeszcze lepiej, sprawiają, że część realizacji dodatkowego przeciążenia do Clamp ...

+0

Nie jestem pewien, dlaczego tak się nie stało (wartość == null)? value: value.Clamp (0, 99999); najpierw. Chyba właśnie próbowałem zmusić Zacisk, by zrobił to automatycznie. Ale tak, to ma więcej sensu, aby nie zerwać go, ponieważ jest zaciśnięcie. –

+0

A teraz nie będzie działać na ciąg))) –

12

Jak powiedział przez @LBushkin Nullable < T> lub T? nie implementuje interfejsu IComparable. Podane rozwiązanie jest w porządku, jednak wolę mieć logikę porównawczą z możliwością niwelowania wewnątrz wyspecjalizowanej klasy w tym zakresie, podążając za Single Responsibility Principle, a także można go użyć do porównywania dowolnych typów zerowalnych.

Na przykład, można utworzyć rodzajowe pustych klasę typu comparer takiego:

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

} 

w tym przypadku byłoby użyć tej klasy tak:

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

przydatny do oszczędności w swoich pomocników biblioteka.

Mam nadzieję, że pomoże!