tags:

views:

646

answers:

4

I was doing some testing with nullable types, and it didn't work quite as I expected:

int? testInt = 0;
Type nullableType = typeof(int?);
Assert.AreEqual(nullableType, testInt.GetType()); // not the same type

My question is why does testInt.GetType() return int, and typeof(int?) return the true nullable type?

According to Enyra this should work. Guess what, it doesn't:

DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable)); //FAIL 

DateTime? test = new DateTime(434523452345);
Assert.IsTrue(test.GetType() == typeof(Nullable<>)); //STILL FAIL
+20  A: 

According to the MSDN :

Calling GetType on a Nullable type causes a boxing operation to be performed when the type is implicitly converted to Object. Therefore GetType always returns a Type object that represents the underlying type, not the Nullable type.

When you box a nullable object, only the underlying type is boxed.

Again, from MSDN :

Boxing a non-null nullable value type boxes the value type itself, not the System.Nullable that wraps the value type.

Romain Verdier
Great that was just what I was looking for! Thanks!
Blake Pettersson
Good find on MSDN.
Nick Berardi
A: 

According to the MSDN

This is stupid! MS should fix this "bug".

majkinetor
This is not a bug it is designed so that you can compare the types the same way that you compare them for reference types. A nullable int will compare to a non-nullable int. The same way a null String will compare to a String with a value.
Nick Berardi
I know its not a bug, thats not the point. This kind of thing breaks the "principle of last surprise" IMO and I still think its stupid. If you need to handle nullable types take them as special case do not change the well known function to return unexpectable thing when 'special' type is feeded into it....
majkinetor
As you can see, its obvious from this question that it confuses people
majkinetor
There are lots of things that confuses us when we don't know the reason behind it. My guess is that it doesn't confuse the person who asked the question anymore.
Svish
I am not guessing. http://en.wikipedia.org/wiki/Principle_of_least_astonishment
majkinetor
A: 

I answered this question a few month ago on my own blog, you can read it here. A nullable type is always of type Nullable<>, so in your case it would be Nullable.

Enyra
Why down vote for a correct answer?
Enyra
+8  A: 

Further to Romain's correct answer, if you want to compare the "real" types (ie, without implicitly converting any nullable type to its underlying type) then you can create an extension method like so:

public static class MyExtensionMethods
{
    public static Type GetRealType<T>(this T source)
    {
        return typeof(T);
    }
}

And then try the following tests:

int? a = 0;
Console.WriteLine(a.GetRealType() == typeof(int?));         // True
Console.WriteLine(a.GetRealType() == typeof(int));          // False

int b = 0;
Console.WriteLine(b.GetRealType() == typeof(int));          // True
Console.WriteLine(b.GetRealType() == typeof(int?));         // False

DateTime? c = DateTime.Now;
Console.WriteLine(c.GetRealType() == typeof(DateTime?));    // True
Console.WriteLine(c.GetRealType() == typeof(DateTime));     // False

DateTime d = DateTime.Now;
Console.WriteLine(d.GetRealType() == typeof(DateTime));     // True
Console.WriteLine(d.GetRealType() == typeof(DateTime?));    // False
LukeH