2011-07-01 18 views
14

Estoy tratando de encontrar una forma de verificar y ver si el valor de un objeto dado es igual a su valor predeterminado. He mirado alrededor y llegar a esto:Verifique si un objeto dado (referencia o tipo de valor) es igual a su valor predeterminado

public static bool IsNullOrDefault<T>(T argument) 
    { 
     if (argument is ValueType || argument != null) 
     { 
      return object.Equals(argument, default(T)); 
     } 
     return true; 
    } 

El problema que estoy teniendo es que yo quiero llamarlo así:

  object o = 0; 
      bool b = Utility.Utility.IsNullOrDefault(o); 

Sí o es un objeto, pero quiero para hacer que descubra el tipo base y verifique el valor predeterminado de eso. El tipo base, en este caso, es un número entero y quiero saber en este caso si el valor es igual a predeterminado (int), no predeterminado (objeto).

Estoy empezando a pensar que esto podría no ser posible.

+0

Por qué no llamarlo como var o = 0; ? – Jethro

+0

No puedo porque obtengo el valor del método 'GetValue' en' PropertyInfo' que solo devuelve un 'object'. – Brian

+0

posible duplicado de [La forma más eficaz de comprobar si un objeto es un tipo de valor] (http://stackoverflow.com/questions/5748661/most-efficient-way-to-check-if-an-object-is-a -value-type) – nawfal

Respuesta

24

En su ejemplo, su número entero está encuadrado y, por lo tanto, su T va a ser object, y el valor predeterminado del objeto es nulo, por lo que no es valioso para usted. Si el objeto es un tipo de valor, puede obtener una instancia del mismo (que sería el valor predeterminado) para usar como una comparación. Algo como:

if (argument is ValueType) 
{ 
    object obj = Activator.CreateInstance(argument.GetType()); 
    return obj.Equals(argument); 
} 

Querría tratar con otras posibilidades antes de recurrir a esto. Marc Gravell's answer trae a colación algunos puntos a considerar, pero para una versión completa de su método, usted podría tener

public static bool IsNullOrDefault<T>(T argument) 
{ 
    // deal with normal scenarios 
    if (argument == null) return true; 
    if (object.Equals(argument, default(T))) return true; 

    // deal with non-null nullables 
    Type methodType = typeof(T); 
    if (Nullable.GetUnderlyingType(methodType) != null) return false; 

    // deal with boxed value types 
    Type argumentType = argument.GetType(); 
    if (argumentType.IsValueType && argumentType != methodType) 
    { 
     object obj = Activator.CreateInstance(argument.GetType()); 
     return obj.Equals(argument); 
    } 

    return false; 
} 
+0

buena solución al problema. – Keith

+1

Otra forma de implementar esto es codificarlo como una extensión: 'bool estático público IsNullOrDeafult (este argumento T)' – scottmgerstl

+0

Como señala Marc Gravell, pero no entendí al principio: cuando un valor que admite nulos está encuadrado es un valor nulo o un valor. P.ej. \t objeto o = (int?) 0; \t Debug.Assert (o.GetType() == typeof (int)); // No int? Por lo tanto, creo que es un error de ofrecer un método genérico donde: \t IsNullOrDefault - devuelve falso, pero \t IsNullOrDefault ((objeto) (int) 0?) - devuelve verdadero ((int) 0?) (Los moldes no son casos de uso reales, pero el boxeo sí ocurre en escenarios útiles.) IMO una mejor solución es pasar en el tipo explícito de tiempo de ejecución. –

4

si o es nulo, en un método no genérico (object), que no tendrán acceso a la tipo original, y no se puede hacer mucho al respecto.

Por lo tanto, la única vez que importa es no anulable tipos de valor, por lo que:

Type type = value.GetType(); 
if(!type.IsValueType) return false; // can't be, as would be null 
if(Nullable.GetUnderlyingType(type) != null) return false; // ditto, Nullable<T> 
object defaultValue = Activator.CreateInstance(type); // must exist for structs 
return value.Equals(defaultValue); 
0

A continuación se solucionaría.

public static bool IsNullOrDefault<T>(T argument) 
{ 
    if (argument is ValueType || argument != null) 
    { 
     return object.Equals(argument, GetDefault(argument.GetType())); 
    } 
    return true; 
} 


public static object GetDefault(Type type) 
{ 
    if(type.IsValueType) 
    { 
     return Activator.CreateInstance(type); 
    } 
    return null; 
} 
1

Ampliando la respuesta de Marc Gravell, consiguiendo el tipo de tiempo de ejecución como un argumento:

// Handles boxed value types 
public static bool IsNullOrDefault([CanBeNull] this object @object, 
    [NotNull] Type runtimeType) 
{ 
    if (@object == null) return true; 

    if (runtimeType == null) throw new ArgumentNullException("runtimeType"); 

    // Handle non-null reference types. 
    if (!runtimeType.IsValueType) return false; 

    // Nullable, but not null 
    if (Nullable.GetUnderlyingType(runtimeType) != null) return false; 

    // Use CreateInstance as the most reliable way to get default value for a value type 
    object defaultValue = Activator.CreateInstance(runtimeType); 

    return defaultValue.Equals(@object); 
} 

Para aquellos de ustedes que pondrá a prueba mi caso de uso, quiero enumerar los valores de las propiedades en un objeto arbitrario, omitiendo las propiedades que establecen sus valores predeterminados (para una visualización más concisa).

Dado que propertyInfo.GetValue (targetObject, null) devuelve un objeto y los tipos de valores están enmarcados, no puedo usar un método genérico. Al pasar propertyInfo.PropertyType como el segundo parámetro de este método, puedo evitar el problema que tiene un método genérico con los tipos de valores encuadrados.

0

Haga un método de extensión

public static class DateExtension 
{ 
    public static bool IsNullOrDefault(this DateTime? value) 
    { 
     return default(DateTime) == value || default(DateTime?) == value; 
    } 
} 
Cuestiones relacionadas