views:

105

answers:

2

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");
}
+12  A: 
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.

thecoop
Nice! Thanks. (I always forget about `<>` in reflection.)
Dan Tao
This will not work in many common situations since the CLR treats `Nullable<T>` as a special type. In particular, it gets boxed into a boxed `T`.
Ani
@Ani: what do you mean? By `T`, I am referring to the `typeof(T)`
thecoop
@thecoop: Explained in an answer.
Ani
+5  A: 

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.

Ani
Very helpful and important points to mention. Fortunately, I was specifically looking to identify if the `PropertyType` property of a `PropertyInfo` was some nullable type; in this case, thecoop's answer works great. But you're right that [no other value type behaves that way](http://stackoverflow.com/questions/3775582/how-is-the-boxing-unboxing-behavior-of-nullablet-possible).
Dan Tao
Haha, that's brilliant: you point me to another question of *yours* that deals with this very matter, except with more clarity and detail. What an exercise in redundancy on my part.
Ani
@Ani: Not at all! I don't think this answer is redundant; it provides some very important insight into the potential pitfalls of a general solution for the problem I posed in my question. I only included that link because I felt it touched on some of the same issues, for those seeking further information.
Dan Tao
@Ani: it was also useful because I didn't see the other question until seeing this. I learnt something new today. :)
Chris