2009-11-20 19 views
26

Deseo descubrir automágicamente cierta información en una clase proporcionada para hacer algo similar a la entrada de formulario. Específicamente, estoy usando el reflejo para devolver un valor de PropertyInfo para cada propiedad. Puedo leer o escribir valores en cada propiedad de mi "formulario", pero si la propiedad se define como "int", no podría, y mi programa ni siquiera debería intentar, escribir un valor nulo.Determinar si la propiedad reflejada puede asignarse nula

¿Cómo puedo usar la reflexión para determinar si a una propiedad determinada se le puede asignar un valor nulo, sin escribir una declaración de cambio para verificar para cada tipo posible? En particular, quiero detectar la diferencia entre tipos encuadrados como "int" vs. "int?", Ya que en el segundo caso I do quiero poder escribir un valor nulo. IsValueType e IsByRef no parecen ver la diferencia.

public class MyClass 
{ 
    // Should tell me I cannot assign a null 
    public int Age {get; set;} 
    public DateTime BirthDate {get; set;} 
    public MyStateEnum State {get; set;} 
    public MyCCStruct CreditCard {get; set;} 

    // Should tell me I can assign a null 
    public DateTime? DateOfDeath {get; set;} 
    public MyFamilyClass Famly {get; set;} 
} 

Tenga en cuenta que necesito para determinar esta información mucho antes de que en realidad intento de escribir el valor, por lo que usar el control de excepciones envuelto alrededor FijarValor no es una opción.

Respuesta

62

Es necesario para manejar null referencias y Nullable<T>, por lo que (a su vez):

bool canBeNull = !type.IsValueType || (Nullable.GetUnderlyingType(type) != null); 

Tenga en cuenta que IsByRef es algo diferente, que le permite elegir entre int y ref int/out int.

+1

Algo en lo que no pensé pero probé su respuesta en contra de las matrices, como int [] (que puede asignarse nulo). Su respuesta también funcionó correctamente para este caso. – David

+2

Las matrices son tipos de referencia, por lo que funcionan igual que las clases. –

+0

Creo que debe tenerse en cuenta que en el OP, hubo ejemplos que utilizan un int? y DateTime ?, por lo que el primer cheque devolvería true (! type.IsValueType). Me gusta de esta manera mejor que la dada en MSDN, pero me extraña por qué agregaste lo que parece ser una verificación redundante. Tal vez, porque quiere lidiar con todos los casos más allá de lo que se solicitó? – pqsk

9

De http://msdn.microsoft.com/en-us/library/ms366789.aspx

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) 

Type sería su PropertyInfo.PropertyType

+1

Eso solo devuelve los nulables, sin embargo. Funciona para DateTime ?, pero no para MyFamilyClass, ya que no es un genérico, pero sigue siendo un tipo al que se le puede asignar un valor nulo –

+0

Sí, eso es correcto. –

+0

Esto funcionó para mí, mientras que la respuesta de Marc no. –

4
PropertyInfo propertyInfo = ... 
bool canAssignNull = 
    !propertyInfo.PropertyType.IsValueType || 
    propertyInfo.PropertyType.IsGenericType && 
     propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) 
+0

Usar PropertyInfo tiene más sobrecarga que usar el tipo directamente. Pero puede ser útil si necesita las características adicionales para otras cosas en el futuro. – TamusJRoyce

0

Marc y Jonas tienen partes para determinar si se puede asignar un tipo genérico nulo.

// A silly example. default(T) will return null if it is nullable. So no reason to check here. Except for the sake of having an example. 
public U AssignValueOrDefault<U>(object item) 
{ 
    if (item == null) 
    { 
     Type type = typeof(U); // Type from Generic Parameter 

     // Basic Types like int, bool, struct, ... can't be null 
     // Except int?, bool?, Nullable<int>, ... 
     bool notNullable = type.IsValueType || 
          (type.IsGenericType && type.GetGenericTypeDefinition() != typeof(Nullable<>))); 

     if (notNullable) 
      return default(T); 
    } 

    return (U)item; 
} 

Nota: la mayoría de las veces puede verificar si la variable es nula. Luego usa el predeterminado (T). Devolverá nulo por defecto del objeto es una clase.

Cuestiones relacionadas