Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
241 views
in Technique[技术] by (71.8m points)

c# - GetType on Nullable Boolean

I was looking into nullable bools when I found this article on Microsoft MSDN

How to: Identify a Nullable Type (C# Programming Guide)

You can use the C# typeof operator to create a Type object that represents a Nullable type.

So I tried checking with a nullable bool:

Console.Write(typeof(bool?)); //System.Nullable`1[System.Boolean]

The article on MSDN says

You can also use the classes and methods of the System.Reflection namespace to generate Type objects that represent Nullable types. However, if you try to obtain type information from Nullable variables at runtime by using the GetType method or the is operator, the result is a Type object that represents the underlying type, not the Nullable type itself.

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.

If this is true I expect to get the same result from .GetType() whether I use a nullable bool or a regular bool. But this is not what happens:

    bool a = new bool();
    Console.Write(a.GetType()); //Prints System.Boolean

    bool? b = new bool?();
    Console.Write(b.GetType()); //Exception!

The exception that occured:

An unhandled exception of type 'System.NullReferenceException' occurred in BoolTest.exe

Additional information: Object reference not set to an instance of an object.

But the object reference is set to an instance of an object. What could be the cause of this error?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your actual question seems to be:

By initializing a Nullable<T> to its default value using its default constructor, for example bool? b = new bool?();, why does accessing b's members such as GetType() throw a NullReferenceException? Doesn't new always return a value, so b can't really be null?

Well, yes and no. Nullable<T> is kind of special. From the C# specs:

4.1.10 Nullable types

[...]

An instance of a nullable type T? has two public read-only properties:

  • A HasValue property of type bool
  • A Value property of type T

An instance for which HasValue is true is said to be non-null. A non-null instance contains a known value and Value returns that value. An instance for which HasValue is false is said to be null. A null instance has an undefined value. Attempting to read the Value of a null instance causes a System.InvalidOperationException to be thrown.

So yes, bool? b = new bool?(); does return an instance: one you only can call HasValue on. Since it returns false, you can't do much else with that instance.

Then the next relevant section:

4.3.1 Boxing conversions

Boxing a value of a nullable-type produces a null reference if it is the null value (HasValue is false)

This is also explained in MSDN: Boxing Nullable Types (C# Programming Guide):

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.

Somewhat further into the specs:

11.3.5 Boxing and unboxing

When a struct type overrides a virtual method inherited from System.Object (such as Equals, GetHashCode, or ToString), invocation of the virtual method through an instance of the struct type does not cause boxing to occur.

GetType() is not overridden by Nullable<T>, so boxing will occur. When you call GetType() or any non-overridden method on a struct, the struct will be boxed to an object before calling that method. In the case of a null Nullable<T>, the result of that boxing operation will be (object)null. Hence the exception.

See also Does calling a method on a value type result in boxing in .NET?.


So, to answer your question:

  • b is not null, it holds a Nullable<bool> with a HasValue indicating false.
  • Calling the non-overridden GetType() method on it, causes the Nullable<bool> struct to be boxed in order to access the underlying method object.GetType().
  • This boxing operation actually doesn't box, but simply returns (object)null.
  • In the end, you're calling ((object)null).GetType(), which throws the NullReferenceException you encounter.

If you're actually looking for a piece of code that can return the type of any variable, even a null Nullable<T>, use something like this:

Type GetType<T>(T obj) 
{ 
    return typeof(T); 
}

Which you can then call like this:

Console.WriteLine(GetType(b));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...