2010-07-20 15 views
9

Sto provando a creare un semplice Clamp (in modo da poter legare i valori di qualsiasi cosa comparabile ... principalmente per i tipi di numero come int, double, ecc.)Tipo generico Nullable utilizzato con IComparable. È possibile?

Il problema è se faccio il seguente Viene visualizzato un messaggio di errore, ma according to MSDN CompareComponable è in grado di gestire valori nulli.
Quote: "Per definizione, qualsiasi oggetto confronta maggiore di null e due riferimenti nulli si confrontano l'uno con l'altro."

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

risposta

7

Ricordate, Int32? è una scorciatoia per Nullable<Int32>. Poiché non implementa IComparable<T>, il tuo codice, come strutturato, non verrà compilato.

È possibile, tuttavia, sovraccaricare il metodo:

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

Naturalmente, se avete intenzione di lavorare con tipi nullable, è necessario definire come si intende bloccare null valori ...

Se in realtà non c'è bisogno di bloccare null valori, può essere più semplice da solo primo controllo per nulla nel vostro getter proprietà:

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

O meglio ancora, renderlo parte della realizzazione del sovraccarico aggiuntivo per Clamp ...

+0

Non sono sicuro del motivo per cui non l'ho fatto (valore == null)? valore: value.Clamp (0, 99999); iniziare con. Credo che stavo solo cercando di forzare il Clamp a farlo automaticamente. Ma sì, in realtà ha più senso non annullarlo visto che sta bloccando. –

+0

E ora non funzionerà per la stringa))) –

12

Come detto da @LBushkin Nullable < T> o T? non implementa l'interfaccia IComparable. La soluzione data è ok, tuttavia preferisco avere la logica di confronto nullable all'interno di una classe specializzata in quella materia, seguendo lo Single Responsibility Principle, e anche che può essere usata per confrontare qualsiasi tipo di Nullable.

Ad esempio, è possibile creare una classe generica tipo di confronto Nullable come questo:

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 questo caso si può usare questa classe come questa:

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 per salvare nei vostri aiutanti biblioteca.

Spero che aiuti!

Problemi correlati