Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I tell if an object's type is Nullable<T> using reflection?

If I have a Type, is there some easy way to tell that it represents a nullable value type using Reflection? Ideally something a little cleaner (and more correct) than:

static bool IsNullable(Type type)
{
    return type.IsValueType && type.Name.StartsWith("Nullable");
}
like image 680
Dan Tao Avatar asked Oct 05 '10 15:10

Dan Tao


2 Answers

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

You might also find Nullable.GetUnderlyingType(Type nullableType) useful, to easily get the T of the typeof(Nullable<T>) you pass in.

like image 195
thecoop Avatar answered Oct 10 '22 10:10

thecoop


Although @theCoop's answer is correct (there is nothing fundamentally wrong in placing his code into the body of the method you've provided), there are some giant gotchas here.

Nullable<T> is treated by the run-time as a 'special' type that has some very peculiar semantics. In particular, when a Nullable<T>is boxed:

  1. If HasValue == true, it behaves just like a boxed T, making it impossible for downsteam code to tell if the created object was produced by boxing a T or by boxing a Nullable<T>. Unboxing to T and Nullable<T> are both possible.
  2. If HasValue == false, boxing simply returns null. Unboxing to T will throw, unboxing to Nullable<T> will succeed, for which HasValue == false.

In either case, boxedNullableObject.GetType() will not reveal that the object was produced by boxing a Nullable<T>. I can't think of any other value-type that exhibits such strange behaviour.

For example, consider:

// Output: "System.Nullable`1[System.Int32]"
Console.WriteLine(typeof(int?));


object boxedNullableInt32WithValue = new int?(0);

// Output: "System.Int32", NOT "System.Nullable`1[System.Int32]"
Console.WriteLine(boxedNullableInt32WithValue.GetType()); 


object boxedNullableInt32WithoutValue = new int?();

// NullReferenceException is thrown
Console.WriteLine(boxedNullableInt32WithoutValue.GetType()); 

Consequently, writing a method such as:

public static bool IsObjectANullableT(this object obj) { ... }

is a really bad idea.

EDIT: On another note, I just realized there is a framework method that does what you need using the same technique as @theCoop's sample:Nullable.GetUnderlyingType.

Usage:

static bool IsNullable(Type type)
{
    return Nullable.GetUnderlyingType(type) != null;
}

EDIT: Just saw that this too was mentioned by @TheCoop in his answer. My mistake.

like image 33
Ani Avatar answered Oct 10 '22 09:10

Ani