Activator.CreateInstance creates value of type T instead of Nullable<T>
Asked Answered
L

1

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

Lucilucia answered 29/5, 2015 at 16:25 Comment(4)
@petelids I'm using VS 2013 Premium and .NET Framework 4.5 and build configuration is Debug. Do you use the same configuration?Lucilucia
This isn't unique to Activator. Console.WriteLine((new Nullable<bool>(false).GetType().FullName)); also just spits out plain Boolean.Embolectomy
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.Gildagildas
Here is relevant blog post by Brad Wilson Creating Nullable<T> When You Don't Know TSystem
N
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]
Nibelungenlied answered 29/5, 2015 at 16:35 Comment(2)
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<T> out of GetType, correct?Gildagildas
@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.Nibelungenlied

© 2022 - 2024 — McMap. All rights reserved.