'Determine if reflected property can be assigned null
I wish to automagically discover some information on a provided class to do something akin to form entry. Specifically I am using reflection to return a PropertyInfo value for each property. I can read or write values to each property from my "form", but if the property is defined as "int", I would not be able to, and my program should not even try, to write a null value.
How can I use reflection to determine if a given property can be assigned a null value, without writing a switch statement to check for every possible type? In particular I want to detect the difference between boxed types like "int" vs. "int?", since in the second case I do want to be able to write a null value. The IsValueType and IsByRef don't seem to see a difference.
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;}
}
Note that I need to determine this information long before I actually attempt to write the value, so using exception handling wrapped around SetValue is not an option.
Solution 1:[1]
You need to handle null references and Nullable<T>, so (in turn):
bool canBeNull = !type.IsValueType || (Nullable.GetUnderlyingType(type) != null);
Note that IsByRef is something different, that allows you to choose between int and ref int / out int.
Solution 2:[2]
From http://msdn.microsoft.com/en-us/library/ms366789.aspx
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
Type would be your PropertyInfo.PropertyType
Solution 3:[3]
PropertyInfo propertyInfo = ...
bool canAssignNull =
!propertyInfo.PropertyType.IsValueType ||
propertyInfo.PropertyType.IsGenericType &&
propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)
Solution 4:[4]
Marc and Jonas both have parts to determine if a generic type can be assigned null.
// 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;
}
Note: Most of the time you can check if the variable is null. Then use default(T). It will return null by default of the object is a class.
Solution 5:[5]
Suppose we have a class:
public class MyClass
{
// Should tell me I cannot assign a null
public int Age { get; set; }
public DateTime BirthDate { get; set; }
public object Family { get; set; }
// Should tell me I can assign a null
public DateTime? DateOfDeath { get; set; }
}
In fact we could assign null to Family property, but as we have not write
public object? Family { get; set; }
we consider it mandatory and want to avoid set it null. Nevertheless if we try offered decision we get True answer:
foreach (PropertyInfo pi in typeof(MyClass).GetProperties())
{
bool canBeNull = !pi.PropertyType.IsValueType
|| (Nullable.GetUnderlyingType(pi.PropertyType) != null);
Console.WriteLine($"{pi.Name}, {canBeNull}");
}
gives us:
Age, False
BirthDate, False
Family, True
DateOfDeath, True
We could use:
bool canBeNull = !pi.PropertyType.IsValueType
&& pi.GetCustomAttributes().Any(a => a.GetType().Name.Contains("NullableAttribute"))
|| (Nullable.GetUnderlyingType(pi.PropertyType) != null);
Now try:
foreach (PropertyInfo pi in typeof(MyClass).GetProperties())
{
bool canBeNull = !pi.PropertyType.IsValueType
&& pi.GetCustomAttributes().Any(a => a.GetType().Name.Contains("NullableAttribute"))
|| (Nullable.GetUnderlyingType(pi.PropertyType) != null);
Console.WriteLine($"{pi.Name}, {canBeNull}");
}
and get:
Age, False
BirthDate, False
Family, False
DateOfDeath, True
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Marc Gravell |
| Solution 2 | Jonas Lincoln |
| Solution 3 | user215303 |
| Solution 4 | |
| Solution 5 | pat8719 |
