开发者

Whats the use of Nullable.GetUnderlyingType, if typeof(int?) is an Int32?

why is typeof int? an Int32

int? x = 1;
Console.WriteLine(x.GetType().Name);

If it is okay then what's the use 开发者_StackOverflow中文版of Nullable.GetUnderlyingType?


Calling GetType() boxes your variable. The CLR has a special rule that Nullable<T> gets boxed to T. So x.GetType will return Int32 instead of Nullable<Int32>.

int? x = 1;
x.GetType() //Int32
typeof(int?) //Nullable<Int32>

Since a Nullable containing null will be boxed to null the following will throw an exception:

int? x = null;
x.GetType() //throws NullReferenceException

To quote MSDN on Boxing Nullable Types:

Objects based on nullable types are only boxed if the object is non-null. If HasValue is false, the object reference is assigned to null instead of boxing

If the object is non-null -- if HasValue is true -- then boxing occurs, but only the underlying type that the nullable object is based on is boxed. Boxing a non-null nullable value type boxes the value type itself, not the System.Nullable<T> that wraps the value type.


This example is a bit confused, because:

int? x = 1;

creates a Nullable<int> like you expect; however:

Type type = x.GetType();

is a call to a non-virtual method on object, which isn't (and can't be) overridden - therefore this is a boxing operation; and Nullable<T> has special boxing rules:

  • if it is empty, it boxes to null
  • if it has a value, the value is boxed and returned

i.e.

int? x = 1;
int y = 1;

box to exactly the same thing.

Therefore, you are passing typeof(int) to GetUnderlyingType.

A more illustrative example of when this helps is when using reflection:

class Foo {
    public int? Bar {get;set;}
}
...
Type type = typeof(Foo); // usually indirectly
foreach(var prop in type.GetProperties()) {
     Type propType = prop.PropertyType,
          nullType = Nullable.GetUnderlyingType(propType);

     if(nullType != null) {
         // special code for handling Nullable<T> properties;
         // note nullType now holds the T
     } else {
         // code for handling other properties
     }
}


Its for when you don't know its Int32.

Example:

    public Type GetNullableUnderlyingType<T>(Nullable<T> obj) 
        where T : struct
    {
        return Nullable.GetUnderlyingType(typeof(Nullable<T>));
    }

Here, you can pass any Nullable object and get it to return it's underlying type.


When you write int? it's as if you've written Nullable<int>. That's the type you're looking for, I think.


Mainly its for dealing with a generic method:: e.g.

public static void SomeMethod<T>(T argument)
{
     if(Nullable.GetUnderlyingType(typeof(T) != null)
     {
             /* special case for nullable code go here */
     }
     else
     {
            /* Do something else T isn't nullable */
     }
}

It's important to know this, as certain things that are very cheap can be wildly expensive on nullable's. For instance, if(argument == null) is normally super cheap, but when done in a generic method on a Nullable<T> is forced to box the argument to get a null reference. Your best bet is to use EqualityComparer<T>.Default which will slow everything else down, but makes nullable's not suffer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜