9

Look at the sample code below

var genericNullableType = typeof(Nullable<>);
var nullableType = genericNullableType.MakeGenericType(typeof(bool));
var returnValue = Activator.CreateInstance(nullableType, (object)false);

For some reason returnValue variable will be of type bool and not bool?. Why is that and how could it be avoided?

UPD: Here is a screenshot from my VS enter image description here

Demarsch
  • 1,419
  • 19
  • 39
  • @petelids I'm using VS 2013 Premium and .NET Framework 4.5 and build configuration is Debug. Do you use the same configuration? – Demarsch May 29 '15 at 16:32
  • 1
    This isn't unique to `Activator`. `Console.WriteLine((new Nullable(false).GetType().FullName));` also just spits out plain Boolean. – vcsjones May 29 '15 at 16:34
  • 1
    There is no way to get a boxed nullable. The runtime has special handling for nullable boxing and will always unwrap it into a boxed value of the underlying type or a null reference. That said it should be castable as a `bool?` so I'm not sure what you are looking for. – Mike Zboray May 29 '15 at 16:35
  • 2
    Here is relevant blog post by Brad Wilson [Creating `Nullable` When You Don't Know T](http://bradwilson.typepad.com/blog/2008/07/creating-nullab.html) – Habib May 29 '15 at 16:39

1 Answers1

15

In this particular case you are using the overload of CreateInstance which returns object. The Nullable<T> is a struct hence to be represented as object it would need to be boxed. Yet Nullable<T> can't actually be boxed by rules of the CLR. Instead the underlying value or null is used. This is why you get a raw bool back here instead of bool?.

Documentation: https://msdn.microsoft.com/en-us/library/ms228597.aspx

EDIT

There seems to be some confusion around determining whether the type of a value is nullable or not. In particular it's been pointed out that the following prints System.Boolean and not System.Nullable``1[System.Boolean]:

var x = (bool?)true;
Console.WriteLine(x.GetType());

This code is also falling prey to boxing. The call to GetType has an implicit boxing operation because it's an invocation of a virtual method on object, not a method on Nullable<T>:

IL_0009: ldloc.0
IL_000a: box valuetype [mscorlib]System.Nullable`1<bool>
IL_000f: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
IL_0014: call void [mscorlib]System.Console::WriteLine(object)

The safest way to print out the actual type of a var value is to do the following trick with generics:

static void PrintType<T>(T value)
{
    Console.WriteLine(typeof(T));
}

PrintType(x);  // Prints System.Nullable`1[System.Boolean]
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Even if another overload of CreateInstance was used, GetType would still internally box because it is non-virtual, thus you would never see a `Nullable` out of GetType, correct? – Mike Zboray May 29 '15 at 16:42
  • @mikez correct. The call to `GetType()` generates an implicit `.box` il opcode which prevents it from spitting out the nullable type. To get the true type to print you need to use generics. Will demonstrate that in just a sec. – JaredPar May 29 '15 at 16:45