Types in C# are divided into two groups:
- reference types (classes);
- value types (primitives, structs).
The variables of the first group contain the references to the object instances. That is why these variables can be null, means pointing to nothing, or not initialized. But as for the latter group, the variables of it are stored directly as values without references. In this case, null cannot be assigned.
At the same time, C# allows to wrap value types into Nullable struct to make them “optional” and capable for later initialization.
This can be done in the following way:
Nullable<int> value = null;
besides, there is a short notation for the same part of code:
int? value = null;
Nice. But wait a second, Nullable is a struct and structs are value types. How come that it can be assigned to null?
Let’s try to create a custom struct and assign it to null:
class Program { struct A { } static void Main(string[] args) { A a = null; } }
Nop, compiler shows us an error in line 7. And the reason is quite fair “Cannot convert null to A”.
Looks like Nullable is not so simple
But how to find out what is going on behind the scene? Let’s create a small sample and check its insides, by this I mean IL code1 (yeah, let’s go hard).
Here is a sample:
class Program { static void Main(string[] args) { Nullable<int> value = null; Console.WriteLine(value); } }
Line 6 here is important just because otherwise the compiler will optimize the output and remove unused variable.
Now let’s check what is going on inside. For this purpose ildasm tool can be used. Here is the output:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 20 (0x14) .maxstack 1 .locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> V_0) IL_0000: ldloca.s V_0 IL_0002: initobj valuetype [mscorlib]System.Nullable`1<int32> IL_0008: ldloc.0 IL_0009: box valuetype [mscorlib]System.Nullable`1<int32> IL_000e: call void [mscorlib]System.Console::WriteLine(object) IL_0013: ret } // end of method Program::Main
The set of IL instructions is pretty clear but anyway here are comments:
- Line 6: variable is defined. Nothing suspicious so far.
- Line 8: here comes the trick, the variable is initialized, but not with a null as it is in the code, instead, the value is the same as its type, that means the following line:
Nullable<int> value = null;
is equal to:
Nullable<int> value = new Nullable<int>();
So the answer is simple: Nullable struct has a special processing by the compiler. And the developer has just a syntactic sugar on top.
1. https://en.wikipedia.org/wiki/List_of_CIL_instructions
Be First to Comment