2009-03-11 16 views
64

Estoy trabajando en un proyecto en donde encuentro que estoy comprobando para el siguiente en muchos, muchos lugares:tipos anulables: la mejor forma de comprobar la nula o cero en C#

if(item.Rate == 0 || item.Rate == null) { } 

más como una curiosidad que nada, ¿cuál es la mejor manera de verificar ambos casos?

He añadido un método de ayuda que es:

public static bool nz(object obj) 
{ 
    var parsedInt = 0; 
    var parsed = int.TryParse(obj.ToString(), out parsedInt); 
    return IsNull(obj) || (parsed && parsedInt == 0); 
} 

¿Hay una mejor manera?

Respuesta

122

me gusta if ((item.Rate ?? 0) == 0) { }

Actualización 1:

También se podría definir como un método de extensión:

public static bool IsNullOrValue(this double? value, double valueToCheck) 
{ 
    return (value??valueToCheck) == valueToCheck; 
} 

Y utilizar de esta manera:

if(item.IsNullOrValue(0)){} // pero no obtienes mucho de él

+1

Cosa de belleza. – Patrick

+3

gracias - ¡muy breve! Estaba preocupado por la legibilidad, pero llegué a la conclusión de que sería perfectamente legible si realmente hubiera entendido el ?? operador. – nailitdown

+2

Debe usar el método de extensión; Si bien es legible en el momento de la escritura, este pequeño código requiere una fracción de pensamiento, lo que significa que si intentas leer el código y lo usa, te distraerás de tu problema principal. – configurator

0
public static bool nz(object obj) 
{ 
    return obj == null || obj.Equals(Activator.CreateInstance(obj.GetType())); 
} 
+1

La reflexión es * lenta *, tenga cuidado con soluciones como esta.No me opongo a la reflexión, pero no lo esperaría en una función "simple" como esta y me tomaría por sorpresa. –

+0

¿Esto realmente comprueba cero? – nailitdown

+0

En realidad, no. Activator.CreateInstance (obj.GetType()) devolverá null para los tipos que aceptan nulos, creo. – configurator

2

Estoy de acuerdo con el uso de ?? operador.

Si usted está tratando con cadenas de usar si (String.IsNullOrEmpty (myStr))

2

Usted ejemplo de código fallará. Si obj es nulo, obj.ToString() dará como resultado una excepción de referencia nula. Cortaría el proceso y verificaría un obj nulo al comienzo de su función auxiliar. En cuanto a su pregunta real, ¿cuál es el tipo que está buscando nulo o cero? En String hay una gran función IsNullOrEmpty, me parece que esto sería un gran uso de los métodos de extensión para implementar un método IsNullOrZero en el int? tipo.

Editar: Recuerde, el '?' es solo el azúcar del compilador para el tipo INullable, por lo que probablemente podría tomar una Inullable como parm y luego compararla con null (parm == null) y si no es nula compare con cero.

+0

aplausos por atrapar ese error - en este proyecto necesito verificarlo contra int ?, double ?, decimal ?, etc. por eso estoy usando "object" – nailitdown

+0

Recuerde, el '?' es solo el compilador de azúcar para el tipo INULLABLE , por lo que probablemente podría tomar un INullable como parm y luego compararlo con null (parm == null) y si no es nulo compare con cero. –

0
class Item{ 
bool IsNullOrZero{ get{return ((this.Rate ?? 0) == 0);}} 
} 
+0

su solución funciona para una propiedad, debería haber especificado que tengo muchas propiedades del mismo artículo para verificar nulo/cero – nailitdown

35

Uso de los genéricos:

static bool IsNullOrDefault<T>(T value) 
{ 
    return object.Equals(value, default(T)); 
} 

//... 
double d = 0; 
IsNullOrDefault(d); // true 
MyClass c = null; 
IsNullOrDefault(c); // true 

Si T Es un tipo referencia, value serán comparados con null (default(T)), de lo contrario, si T es una value type, digamos doble, default(t) es 0d, para bool es false, para char es '\0' y así sucesivamente ...

1

¿Hay una manera mejor?

Bueno, si realmente está buscando una mejor manera, probablemente pueda agregar otra capa de abstracción además de Rate. Bueno, aquí es algo que acabo de idear usando el Patrón de Diseño Nullable.

 
using System; 
using System.Collections.Generic; 

namespace NullObjectPatternTest 
{ 
    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      var items = new List 
          { 
           new Item(RateFactory.Create(20)), 
           new Item(RateFactory.Create(null)) 
          }; 

      PrintPricesForItems(items); 
     } 

     private static void PrintPricesForItems(IEnumerable items) 
     { 
      foreach (var item in items) 
       Console.WriteLine("Item Price: {0:C}", item.GetPrice()); 
     } 
    } 

    public abstract class ItemBase 
    { 
     public abstract Rate Rate { get; } 
     public int GetPrice() 
     { 
      // There is NO need to check if Rate == 0 or Rate == null 
      return 1 * Rate.Value; 
     } 
    } 

    public class Item : ItemBase 
    { 
     private readonly Rate _Rate; 
     public override Rate Rate { get { return _Rate; } } 
     public Item(Rate rate) { _Rate = rate; } 
    } 

    public sealed class RateFactory 
    { 
     public static Rate Create(int? rateValue) 
     { 
      if (!rateValue || rateValue == 0) 
       return new NullRate(); 
      return new Rate(rateValue); 
     } 
    } 

    public class Rate 
    { 
     public int Value { get; set; } 
     public virtual bool HasValue { get { return (Value > 0); } } 
     public Rate(int value) { Value = value; } 
    } 

    public class NullRate : Rate 
    { 
     public override bool HasValue { get { return false; } } 
     public NullRate() : base(0) { } 
    } 
} 
+1

, creo que tiene razón en que la eliminación de valores nulos en una etapa anterior hubiera sido el camino a seguir – nailitdown

+0

No exactamente. Hay un concepto llamado "refactorización". Puede refactorizar su código para obtener un patrón mejor o una mejor estructura. Siempre puede * eliminar * valores anulables en etapas posteriores. – Sung

0

No se olvide, para cuerdas, siempre se puede utilizar:

String.IsNullOrEmpty(str) 

En lugar de:

str==null || str=="" 
+1

La pregunta se compara con "0", no es una cadena vacía. – Sung

16

Esto es realmente sólo una expansión de la respuesta aceptada Freddy Ríos sólo usando Generics.

public static bool IsNullOrDefault<T>(this Nullable<T> value) where T : struct 
{ 
    return default(T).Equals(value.GetValueOrDefault()); 
} 

public static bool IsValue<T>(this Nullable<T> value, T valueToCheck) where T : struct 
{ 
    return valueToCheck.Equals((value ?? valueToCheck)); 
} 

NOTA que no necesitamos para comprobar predeterminado (T) para nula, ya que se trata de cualquiera de los tipos de valor o estructuras! Esto también significa que podemos suponer con seguridad que T valueToCheck no será nulo; ¿Recuerda aquí que T? es abreviado Nullable <T> por lo que al agregar la extensión a Nullable <T> obtenemos el método en int ?, double ?, bool? etc.

Ejemplos:

double? x = null; 
x.IsNullOrDefault(); //true 

int? y = 3; 
y.IsNullOrDefault(); //false 

bool? z = false; 
z.IsNullOrDefault(); //true 
21

Aunque me gusta bastante la respuesta aceptada, creo que, por lo completo, esta opción debe ser mencionado, así:

if (item.Rate.GetValueOrDefault() == 0) { } 

Esta solución


¹ Esto no debe influir en su decisión, sin embargo, ya que estos tipos de micro-optimización es poco probable que alguna diferencia.

Cuestiones relacionadas