2010-07-20 21 views
9

Estoy tratando de crear una abrazadera simple (para poder enlazar los valores de cualquier cosa comparable ... principalmente para tipos de números como int, double, etc.)Tipo genérico anulable utilizado con IComparable. ¿Es posible?

El problema es si hago lo siguiente Me sale un error, pero according to MSDN CompareTo de IComparable se supone que es capaz de manejar valores nulos.
Cita: "Por definición, cualquier objeto se compara mayor que nulo, y dos referencias nulas se comparan entre sí".

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

Respuesta

7

Recuerde, Int32? es una abreviatura de Nullable<Int32>. Como Nullable<T> no implementa IComparable<T>, su código, como estructurado, no se compilará.

Puede, sin embargo, sobrecargar el método:

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

Por supuesto, si usted está pensando en trabajar con tipos anulables, usted tiene que definir cómo va a sujetar null valores ...

Si no necesita realmente para sujetar null valores, puede ser más sencillo que solo cheque por primera nulo en su propiedad de captador:

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

O mejor aún, que sea parte de la aplicación de la sobrecarga adicional para Clamp ...

+0

No estoy seguro de por qué no lo hice (valor == nulo)? valor: value.Clamp (0, 99999); para empezar. Creo que solo estaba tratando de obligar a la pinza a hacerlo automáticamente. Pero sí, en realidad tiene más sentido no anularlo ya que está bloqueando. –

+0

Y ahora no funcionará para la cadena))) –

12

Según lo dicho por @LBushkin anulable < T> o T? no implementa la interfaz IComparable. La solución dada está bien, sin embargo, prefiero tener la lógica de comparación nullable dentro de una clase especializada en ese asunto, siguiendo el Single Responsibility Principle, y también que se puede usar para comparar cualquier tipo de Nullable.

Por ejemplo, se podría crear una clase genérica anulable tipo comparador de esta manera:

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

} 

En este caso se usaría esta clase como esta:

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

práctico para guardar en sus ayudantes biblioteca.

Espero que ayude!

Cuestiones relacionadas