{"id":416218,"date":"2024-06-30T00:49:37","date_gmt":"2024-06-30T00:49:37","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=416218"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=416218","title":{"rendered":"<span>Check how you remember nullable value types. Let&#8217;s peek under the hood<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/292\/bc3\/02b\/292bc302b579fa41d1521e92558c2d55.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/292\/bc3\/02b\/292bc302b579fa41d1521e92558c2d55.png\"\/><\/div>\n<p>  Recently nullable reference types have become trendy. Meanwhile, the good old nullable value types are still here and actively used. How well do you remember the nuances of working with them? Let&#8217;s jog your memory or test your knowledge by reading this article. Examples of C# and IL code, references to the CLI specification, and CoreCLR code are provided. Let&#8217;s start with an interesting case.<br \/>  <a name=\"habracut\"><\/a><br \/>  <b>Note<\/b>. If you are interested in nullable reference types, you can read several articles by my colleagues: &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0631\/\">Nullable Reference types in C# 8.0 and static analysis<\/a>&#171;, &#171;<a href=\"https:\/\/www.viva64.com\/en\/b\/0764\/\">Nullable Reference will not protect you, and here is the proof<\/a>&#171;.<\/p>\n<p>  Take a look at the sample code below and answer what will be output to the console. And, just as importantly, why. Just let&#8217;s agree right away that you will answer as it is: without compiler hints, documentation, reading literature, or anything like that. \ud83d\ude42<\/p>\n<pre><code class=\"cs\">static void NullableTest() {   int? a = null;   object aObj = a;    int? b = new int?();   object bObj = b;    Console.WriteLine(Object.ReferenceEquals(aObj, bObj)); \/\/ True or False? }<\/code><\/pre>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/bbf\/9a2\/dc4\/bbf9a2dc4547378c0be25a33084e64ae.png\" alt=\"image2.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/bbf\/9a2\/dc4\/bbf9a2dc4547378c0be25a33084e64ae.png\"\/><\/div>\n<p>  Well, let&#8217;s do some thinking. Let&#8217;s take a few main lines of thought that I think may arise.<\/p>\n<p>  <b>1. Assume that <i>int? <\/i>is a reference type.<\/b><\/p>\n<p>  Let&#8217;s reason, that <i>int? <\/i>is a reference type. In this case, <i>null<\/i> will be stored in <i>a<\/i>, and it will also be stored in <i>aObj<\/i> after assignment. A reference to an object will be stored in <i>b<\/i>. It will also be stored in <i>bObj<\/i> after assignment. As a result, <i>Object.ReferenceEquals<\/i> will take <i>null<\/i> and a non-null reference to the object as arguments, so\u2026<\/p>\n<p>  <b>That needs no saying, the answer is False!<\/b><\/p>\n<p>  <b>2. Assume that <i>int?<\/i> is a value type.<\/b><\/p>\n<p>  Or maybe you doubt that <i>int?<\/i> is a reference type? And you are sure of this, despite the <i>int? a = null <\/i>expression? Well, let&#8217;s go from the other side and start from the fact that <i>int?<\/i> is a value type.<\/p>\n<p>  In this case, the expression <i>int? a = null<\/i> looks a bit strange, but let&#8217;s assume that C# got some extra syntactic sugar. Turns out, <i>a<\/i> stores an object. So does <i>b<\/i>. When initializing <i>aObj<\/i> and <i>bObj<\/i> variables, objects stored in <i>a<\/i> and <i>b<\/i> will be boxed, resulting in different references being stored in <i>aObj<\/i> and <i>bObj<\/i>. So, in the end, <i>Object.ReferenceEquals<\/i> takes references to different objects as arguments, therefore\u2026<\/p>\n<p>  <b>That needs no saying, the answer is False!<\/b><\/p>\n<p>  <b>3. We assume that here we use <i>Nullable&lt;T><\/i>.<\/b><\/p>\n<p>  Let&#8217;s say you didn&#8217;t like the options above. Because you know perfectly well that there is no <i>int?<\/i>, but there is a value type <i>Nullable&lt;T><\/i>, and in this case <i>Nullable&lt;int><\/i> will be used. You also realize that <i>a<\/i> and<i> b<\/i> will actually have the same objects. With that, you remember that storing values in <i>aObj<\/i> and <i>bObj<\/i> will result in boxing. At long last, we&#8217;ll get references to different objects. Since <i>Object.ReferenceEquals<\/i> gets references to the different objects\u2026<\/p>\n<p>  <b>That needs no saying, the answer is False!<\/b><\/p>\n<p>  <b>4. \ud83d\ude09<\/b><\/p>\n<p>  For those who started from value types \u2014 if a suspicion crept into your mind about comparing links, you can view the documentation for <i>Object.ReferenceEquals<\/i> at <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.object.referenceequals?view=netcore-3.1\">docs.microsoft.com<\/a>. In particular, it also touches on the topic of value types and boxing\/unboxing. Except for the fact that it describes the case, when instances of value types are passed directly to the method, whereas we made the boxing separately, but the main point is the same.<\/p>\n<p>  <i>When comparing value types, if objA and objB are value types, they are boxed before they are passed to the ReferenceEquals method. This means that <b>if both objA and objB represent the same instance of a value type<\/b>, the ReferenceEquals <b>method nevertheless returns false<\/b>, as the following example shows.<\/i><\/p>\n<p>  Here we could have ended the article, but the thing is that\u2026 the correct answer is <b>True<\/b>.<\/p>\n<p>  Well, let&#8217;s figure it out.<\/p>\n<h2>Investigation<\/h2>\n<p>  There are two ways \u2014 simple and interesting.<\/p>\n<h3>Simple way<\/h3>\n<p>  <i>int?<\/i> is <i>Nullable&lt;int><\/i>. Open <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.nullable-1?view=netcore-3.1\">documentation on <i>Nullable&lt;T><\/i><\/a>, where we look at the section &#171;Boxing and Unboxing&#187;. Well, that&#8217;s all, see the behavior description. But if you want more details, welcome to the interesting path. \ud83d\ude09<\/p>\n<h3>Interesting way<\/h3>\n<p>  There won&#8217;t be enough documentation on this path. It describes the behavior, but does not answer the question &#8216;why&#8217;?<\/p>\n<p>  What are actually <i>int?<\/i> and <i>null<\/i> in the given context? Why does it work like this? Are there different commands used in the IL code or not? Is behavior different at the CLR level? Is it another kind of magic?<\/p>\n<p>  Let&#8217;s start by analyzing the <i>int?<\/i> entity to recall the basics, and gradually get to the initial case analysis. Since C# is a rather &#171;sugary&#187; language, we will sometimes refer to the IL code to get to the bottom of things (yes, C# documentation is not our cup of tea today).<\/p>\n<h4>int?, Nullable&lt;T><\/h4>\n<p>  Here we will look at the basics of nullable value types in general: what they are, what they are compiled into in IL, etc. The answer to the question from the case at the very beginning of the article is discussed in the next section.<\/p>\n<p>  Let&#8217;s look at the following code fragment:<\/p>\n<pre><code class=\"cs\">int? aVal = null; int? bVal = new int?(); Nullable&lt;int> cVal = null; Nullable&lt;int> dVal = new Nullable&lt;int>();<\/code><\/pre>\n<p>  Although the initialization of these variables looks different in C#, the same IL code will be generated for all of them.<\/p>\n<pre><code class=\"cs\">.locals init (valuetype [System.Runtime]System.Nullable`1&lt;int32> V_0,               valuetype [System.Runtime]System.Nullable`1&lt;int32> V_1,               valuetype [System.Runtime]System.Nullable`1&lt;int32> V_2,               valuetype [System.Runtime]System.Nullable`1&lt;int32> V_3)  \/\/ aVal ldloca.s V_0 initobj  valuetype [System.Runtime]System.Nullable`1&lt;int32>  \/\/ bVal ldloca.s V_1 initobj  valuetype [System.Runtime]System.Nullable`1&lt;int32>  \/\/ cVal ldloca.s V_2 initobj  valuetype [System.Runtime]System.Nullable`1&lt;int32>  \/\/ dVal ldloca.s V_3 initobj  valuetype [System.Runtime]System.Nullable`1&lt;int32><\/code><\/pre>\n<p>  As you can see, in C# everything is heartily flavored with syntactic sugar for our greater good. But in fact:<\/p>\n<ul>\n<li><i>int?<\/i> is a value type.<\/li>\n<li><i>int?<\/i> is the same as <i>Nullable&lt;int>.<\/i> The IL code works with <i>Nullable&lt;int32><\/i><\/li>\n<li><i>int? aVal = null<\/i> is the same as <i>Nullable&lt;int> aVal =<\/i> <i>new Nullable&lt;int>()<\/i>. In IL, this is compiled to an <i>initobj<\/i> instruction that performs default initialization by the loaded address.<\/li>\n<\/ul>\n<p>  Let&#8217;s consider this code:<\/p>\n<pre><code class=\"cs\">int? aVal = 62;<\/code><\/pre>\n<p>  We&#8217;re done with the default initialization \u2014 we saw the related IL code above. What happens here when we want to initialize <i>aVal<\/i> with the value 62?<\/p>\n<p>  Look at the IL code:<\/p>\n<pre><code class=\"cs\">.locals init (valuetype [System.Runtime]System.Nullable`1&lt;int32> V_0) ldloca.s   V_1 ldc.i4.s   62 call       instance void valuetype             [System.Runtime]System.Nullable`1&lt;int32>::.ctor(!0)<\/code><\/pre>\n<p>  Again, nothing complicated \u2014 the <i>aVal<\/i> address pushes onto the evaluation stack, as well as the value 62. After the constructor with the signature <i>Nullable&lt;T>(T) <\/i>is called. In other words, the following two statements will be completely identical:<\/p>\n<pre><code class=\"cs\">int? aVal = 62; Nullable&lt;int> bVal = new Nullable&lt;int>(62);<\/code><\/pre>\n<p>  You can also see this after checking out the IL code again:<\/p>\n<pre><code class=\"cs\">\/\/ int? aVal; \/\/ Nullable&lt;int> bVal; .locals init (valuetype [System.Runtime]System.Nullable`1&lt;int32> V_0,               valuetype [System.Runtime]System.Nullable`1&lt;int32> V_1)  \/\/ aVal = 62 ldloca.s   V_0 ldc.i4.s   62 call       instance void valuetype                            [System.Runtime]System.Nullable`1&lt;int32>::.ctor(!0)  \/\/ bVal = new Nullable&lt;int>(62) ldloca.s   V_1 ldc.i4.s   62 call       instance void valuetype                            [System.Runtime]System.Nullable`1&lt;int32>::.ctor(!0)<\/code><\/pre>\n<p>  And what about the checks? What does this code represent?<\/p>\n<pre><code class=\"cs\">bool IsDefault(int? value) => value == null;<\/code><\/pre>\n<p>  That&#8217;s right, for better understanding, we will again refer to the corresponding IL code.<\/p>\n<pre><code class=\"cs\">.method private hidebysig instance bool IsDefault(valuetype [System.Runtime]System.Nullable`1&lt;int32> 'value') cil managed {   .maxstack  8   ldarga.s   'value'   call       instance bool valuetype               [System.Runtime]System.Nullable`1&lt;int32>::get_HasValue()   ldc.i4.0   ceq   ret }<\/code><\/pre>\n<p>  As you may have guessed, there is actually no <i>null<\/i> \u2014 all that happens is accessing the <i>Nullable&lt;T>.HasValue<\/i> property. In other words, the same logic in C# can be written more explicitly in terms of the entities used, as follows.<\/p>\n<pre><code class=\"cs\">bool IsDefaultVerbose(Nullable&lt;int> value) => !value.HasValue;<\/code><\/pre>\n<p>  IL code:<\/p>\n<pre><code class=\"cs\">.method private hidebysig instance bool  IsDefaultVerbose(valuetype [System.Runtime]System.Nullable`1&lt;int32> 'value') cil managed {   .maxstack  8   ldarga.s   'value'   call       instance bool valuetype               [System.Runtime]System.Nullable`1&lt;int32>::get_HasValue()   ldc.i4.0   ceq   ret }<\/code><\/pre>\n<p>  Let&#8217;s recap. <\/p>\n<ul>\n<li>Nullable value types are implemented using the <i>Nullable&lt;T><\/i> type;<\/li>\n<li><i>int?<\/i> is actually a constructed type of the unbound generic value type <i>Nullable&lt;T><\/i>;<\/li>\n<li><i>int? a = null <\/i>is the initialization of an object of <i>Nullable&lt;int><\/i> type with the default value, no <i>null<\/i> is actually present here;<\/li>\n<li><i>if (a == null)<\/i> \u2014 again, there is no <i>null<\/i>, there is a call of the <i>Nullable&lt;T>.HasValue<\/i> property.<\/li>\n<\/ul>\n<p>  The source code of the <i>Nullable&lt;T><\/i> type can be viewed, for example, on GitHub in the dotnet\/runtime repository \u2014 a <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/master\/src\/libraries\/System.Private.CoreLib\/src\/System\/Nullable.cs\">direct link to the source code file<\/a>. There&#8217;s not much code there, so check it out just for kicks. From there, you can learn (or recall) the following facts.<\/p>\n<p>  For convenience, the <i>Nullable&lt;T><\/i> type defines:<\/p>\n<ul>\n<li>implicit conversion operator from <i>T<\/i> to <i>Nullable&lt;T<\/i>>;<\/li>\n<li>explicit conversion operator from <i>Nullable&lt;T><\/i> to <i>T<\/i>.<\/li>\n<\/ul>\n<p>  The main logic of work is implemented by two fields (and corresponding properties):<\/p>\n<ul>\n<li><i>T value<\/i> \u2014 the value itself, the wrapper over which is <i>Nullable&lt;T><\/i>;<\/li>\n<li><i>bool hasValue<\/i> \u2014 the flag indicating &#171;whether the wrapper contains a value&#187;. It&#8217;s in quotation marks, since in fact <i>Nullable&lt;T><\/i> always contains a value of type <i>T<\/i>.<\/li>\n<\/ul>\n<p>  Now that we&#8217;ve refreshed our memory about nullable value types, let&#8217;s see what&#8217;s going on with the boxing.<\/p>\n<h4>Nullable&lt;T> boxing<\/h4>\n<p>  Let me remind you that when boxing an object of a value type, a new object will be created on the heap. The following code snippet illustrates this behavior:<\/p>\n<pre><code class=\"cs\">int aVal = 62; object obj1 = aVal; object obj2 = aVal;  Console.WriteLine(Object.ReferenceEquals(obj1, obj2));<\/code><\/pre>\n<p>  The result of comparing references is expected to be <i>false<\/i>. It is due to 2 boxing operations and creating of 2 objects whose references were stored in <i>obj1<\/i> and <i>obj2<\/i><\/p>\n<p>  Now let&#8217;s change <i>int<\/i> to <i>Nullable&lt;int><\/i>.<\/p>\n<pre><code class=\"cs\">Nullable&lt;int> aVal = 62; object obj1 = aVal; object obj2 = aVal;  Console.WriteLine(Object.ReferenceEquals(obj1, obj2));<\/code><\/pre>\n<p>  The result is expectedly <i>false<\/i>.<\/p>\n<p>  And now, instead of 62, we write the default value.<\/p>\n<pre><code class=\"cs\">Nullable&lt;int> aVal = new Nullable&lt;int>(); object obj1 = aVal; object obj2 = aVal;  Console.WriteLine(Object.ReferenceEquals(obj1, obj2));<\/code><\/pre>\n<p>  Aaand\u2026 the result is unexpectedly <i>true<\/i>. One might wonder that we have all the same 2 boxing operations, two created objects and references to two different objects, but the result is <i>true<\/i>!<\/p>\n<p>  Yeah, it&#8217;s probably sugar again, and something has changed at the IL code level! Let&#8217;s see.<\/p>\n<p>  Example N1.<\/p>\n<p>  C# code:<\/p>\n<pre><code class=\"cs\">int aVal = 62; object aObj = aVal;<\/code><\/pre>\n<p>  IL code:<\/p>\n<pre><code class=\"cs\">.locals init (int32 V_0,               object V_1)  \/\/ aVal = 62 ldc.i4.s   62 stloc.0  \/\/ aVal boxing ldloc.0 box        [System.Runtime]System.Int32  \/\/ saving the received reference in aObj stloc.1<\/code><\/pre>\n<p>  Example N2.<\/p>\n<p>  C# code:<\/p>\n<pre><code class=\"cs\">Nullable&lt;int> aVal = 62; object aObj = aVal;<\/code><\/pre>\n<p>  IL code:<\/p>\n<pre><code class=\"cs\">.locals init (valuetype [System.Runtime]System.Nullable`1&lt;int32> V_0,               object V_1)  \/\/ aVal = new Nullablt&lt;int>(62) ldloca.s   V_0 ldc.i4.s   62 call       instance void            valuetype [System.Runtime]System.Nullable`1&lt;int32>::.ctor(!0)  \/\/ aVal boxing ldloc.0 box        valuetype [System.Runtime]System.Nullable`1&lt;int32>  \/\/ saving the received reference in aObj stloc.1<\/code><\/pre>\n<p>  Example N3.<\/p>\n<p>  C# code:<\/p>\n<pre><code class=\"cs\">Nullable&lt;int> aVal = new Nullable&lt;int>(); object aObj = aVal;<\/code><\/pre>\n<p>  IL code:<\/p>\n<pre><code class=\"cs\">.locals init (valuetype [System.Runtime]System.Nullable`1&lt;int32> V_0,               object V_1)  \/\/ aVal = new Nullable&lt;int>() ldloca.s   V_0 initobj    valuetype [System.Runtime]System.Nullable`1&lt;int32>  \/\/ aVal boxing ldloc.0 box        valuetype [System.Runtime]System.Nullable`1&lt;int32>  \/\/ saving the received reference in aObj stloc.1<\/code><\/pre>\n<p>  As we can see, in all cases boxing happens in the same way \u2014 values of local variables are pushed onto the evaluation stack (<i>ldloc<\/i> instruction). After that the boxing itself occurs by calling the <i>box<\/i> command, which specifies what type we will be boxing.<\/p>\n<p>  Next we refer to <a href=\"https:\/\/www.ecma-international.org\/publications\/files\/ECMA-ST\/ECMA-335.pdf\">Common Language Infrastructure specification<\/a>, see the description of the <i>box<\/i> command, and find an interesting note regarding nullable types:<\/p>\n<p>  If typeTok is a value type, the box instruction converts val to its boxed form.\u2026 <i>If it is a nullable type, this is done by inspecting val&#8217;s HasValue property; if it is false, a null reference is pushed onto the stack; otherwise, the result of boxing val&#8217;s Value property is pushed onto the stack.<\/i><\/p>\n<p>  This leads to several conclusions that dot the &#8216;i&#8217;:<\/p>\n<ul>\n<li>the state of the <i>Nullable&lt;T><\/i> object is taken into account (the <i>HasValue<\/i> flag we discussed earlier is checked). If <i>Nullable&lt;T><\/i> does not contain a value (<i>HasValue<\/i> \u2014 <i>false<\/i>), the result of boxing is <i>null<\/i>;<\/li>\n<li>if <i>Nullable&lt;T><\/i> contains a value (<i>HasValue<\/i> &#8212;<i> true<\/i>), it is not a <i>Nullable&lt;T><\/i> object that is boxed, but an instance of type <i>T<\/i> that is stored in the <i>value<\/i> field of type <i>Nullable&lt;T<\/i>>;<\/li>\n<li>specific logic for handling <i>Nullable&lt;T><\/i> boxing is not implemented at the C# level or even at the IL level \u2014 it is implemented in the CLR.<\/li>\n<\/ul>\n<p>  Let&#8217;s go back to the examples with <i>Nullable&lt;T><\/i> that we touched upon above.<\/p>\n<p>  First:<\/p>\n<pre><code class=\"cs\">Nullable&lt;int> aVal = 62; object obj1 = aVal; object obj2 = aVal;  Console.WriteLine(Object.ReferenceEquals(obj1, obj2));<\/code><\/pre>\n<p>  The state of the instance before the boxing:<\/p>\n<ul>\n<li><i>T<\/i> -> <i>int<\/i>;<\/li>\n<li><i>value<\/i> -> <i>62<\/i>;<\/li>\n<li><i>hasValue<\/i> -> <i>true<\/i>.<\/li>\n<\/ul>\n<p>  The value 62 is boxed twice. As we remember, in this case, instances of the <i>int<\/i> type are boxed, not <i>Nullable&lt;int><\/i>. Then 2 new objects are created, and 2 references to different objects are obtained, the result of their comparing is <i>false<\/i>.<\/p>\n<p>  Second:<\/p>\n<pre><code class=\"cs\">Nullable&lt;int> aVal = new Nullable&lt;int>(); object obj1 = aVal; object obj2 = aVal;  Console.WriteLine(Object.ReferenceEquals(obj1, obj2));<\/code><\/pre>\n<p>  The state of the instance before the boxing:<\/p>\n<ul>\n<li><i>T<\/i> -> <i>int<\/i>;<\/li>\n<li><i>value<\/i> -> <i>default<\/i> (in this case, <i>0<\/i> \u2014 a default value for <i>int<\/i>);<\/li>\n<li><i>hasValue<\/i> -> <i>false<\/i>.<\/li>\n<\/ul>\n<p>  Since is <i>hasValue<\/i> is <i>false<\/i>, objects are not created. The boxing operation returns <i>null<\/i> which is stored in variables <i>obj1<\/i> and <i>obj2<\/i>. Comparing these values is expected to return <i>true<\/i>.<\/p>\n<p>  In the original example, which was at the very beginning of the article, exactly the same thing happens:<\/p>\n<pre><code class=\"cs\">static void NullableTest() {   int? a = null;       \/\/ default value of Nullable&lt;int>   object aObj = a;     \/\/ null    int? b = new int?(); \/\/ default value of Nullable&lt;int>   object bObj = b;     \/\/ null    Console.WriteLine(Object.ReferenceEquals(aObj, bObj)); \/\/ null == null }<\/code><\/pre>\n<p>  For the sake of interest, let&#8217;s look at the CoreCLR source code from the <a href=\"https:\/\/github.com\/dotnet\/runtime\">dotnet\/runtime<\/a> repository mentioned earlier. We are interested in the file <a href=\"https:\/\/github.com\/dotnet\/runtime\/blob\/master\/src\/coreclr\/src\/vm\/object.cpp\">object.cpp<\/a>, specifically, the <i>Nullable::Bo<\/i>x method with the logic we need:<\/p>\n<pre><code class=\"cs\">OBJECTREF Nullable::Box(void* srcPtr, MethodTable* nullableMT) {   CONTRACTL   {     THROWS;     GC_TRIGGERS;     MODE_COOPERATIVE;   }   CONTRACTL_END;    FAULT_NOT_FATAL();      \/\/ FIX_NOW: why do we need this?    Nullable* src = (Nullable*) srcPtr;    _ASSERTE(IsNullableType(nullableMT));   \/\/ We better have a concrete instantiation,    \/\/ or our field offset asserts are not useful   _ASSERTE(!nullableMT->ContainsGenericVariables());    if (!*src->HasValueAddr(nullableMT))     return NULL;    OBJECTREF obj = 0;   GCPROTECT_BEGININTERIOR (src);   MethodTable* argMT = nullableMT->GetInstantiation()[0].AsMethodTable();   obj = argMT->Allocate();   CopyValueClass(obj->UnBox(), src->ValueAddr(nullableMT), argMT);   GCPROTECT_END ();    return obj; }<\/code><\/pre>\n<p>  Here we have everything we discussed earlier. If we don&#8217;t store the value, we return <i>NULL<\/i>:<\/p>\n<pre><code class=\"cs\">if (!*src->HasValueAddr(nullableMT))     return NULL;<\/code><\/pre>\n<p>  Otherwise we initiate the boxing:<\/p>\n<pre><code class=\"cs\">OBJECTREF obj = 0; GCPROTECT_BEGININTERIOR (src); MethodTable* argMT = nullableMT->GetInstantiation()[0].AsMethodTable(); obj = argMT->Allocate(); CopyValueClass(obj->UnBox(), src->ValueAddr(nullableMT), argMT);<\/code><\/pre>\n<p>  <\/p>\n<h2>Conclusion<\/h2>\n<p>  You&#8217;re welcome to show the example from the beginning of the article to your colleagues and friends just for kicks. Will they give the correct answer and justify it? If not, share this article with them. If they do it \u2014 well, kudos to them!<\/p>\n<p>  I hope it was a small but exciting adventure. \ud83d\ude42<\/p>\n<p>  <b>P.S.<\/b> Someone might have a question: how did we happen to dig that deep in this topic? We were writing a new diagnostic rule in <a href=\"https:\/\/www.viva64.com\/en\/pvs-studio\/\">PVS-Studio<\/a> related to <i>Object.ReferenceEquals<\/i> working with arguments, one of which is represented by a value type. Suddenly it turned out that with <i>Nullable&lt;T><\/i> there is an unexpected subtlety in the behavior when boxing. We looked at the IL code \u2014 there was nothing special about the <i>box<\/i>. Checked out the CLI specification \u2014 and gotcha! The case promised to be rather exceptional and noteworthy, so here&#8217;s the article right in front of you.<\/p>\n<p>  <b>P.P.S.<\/b> By the way, recently, I have been spending more time on Twitter where I post some interesting code snippets and retweet some news in the .NET world and so on. Feel free to look through it and follow me if you want (<a href=\"https:\/\/twitter.com\/_SergVasiliev_\">link to the profile<\/a>).<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><\/p>\n<div class=\"tm-article-poll-container\"><!--[--><\/p>\n<div class=\"tm-article-poll tm-article-poll_variant-bordered\">\n<div class=\"tm-notice tm-notice_positive tm-article-poll__notice\"><!----><\/p>\n<div class=\"tm-notice__inner\"><!----><\/p>\n<div class=\"tm-notice__content\" data-test-id=\"notice-content\"><!--[--><span>\u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u043f\u0440\u043e\u0441\u0435. <a rel=\"nofollow\" href=\"\/kek\/v1\/auth\/habrahabr\/?back=\/ru\/companies\/pvs-studio\/articles\/525816\/&#038;hl=ru\">\u0412\u043e\u0439\u0434\u0438\u0442\u0435<\/a>, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430.<\/span><!--]--><\/div>\n<\/div>\n<\/div>\n<p><!--[--><\/p>\n<div class=\"tm-article-poll__header\">Did you answer correctly the question at the beginning of the article and justify your answer?<\/div>\n<div class=\"tm-article-poll__answers\"><!--[--><\/p>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">50% <\/span><span class=\"tm-article-poll__answer-label\">Yes<\/span><span class=\"tm-article-poll__answer-votes\">1<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 50%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent tm-article-poll__answer-percent_winning\">50% <\/span><span class=\"tm-article-poll__answer-label\">No<\/span><span class=\"tm-article-poll__answer-votes\">1<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress tm-article-poll__answer-progress_winning\" style=\"width: 50%\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">0% <\/span><span class=\"tm-article-poll__answer-label\">Didn&#8217;t answer<\/span><span class=\"tm-article-poll__answer-votes\">0<\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width: 0%\"><\/div>\n<\/div>\n<\/div>\n<p><!--]--><\/div>\n<div class=\"tm-article-poll__stats\"> \u041f\u0440\u043e\u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043b\u0438 2 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.    \u0412\u043e\u0437\u0434\u0435\u0440\u0436\u0430\u043b\u0441\u044f 1 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c. <\/div>\n<p><!--]--><\/div>\n<p><!--]--><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/525816\/\"> https:\/\/habr.com\/ru\/articles\/525816\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/post_images\/292\/bc3\/02b\/292bc302b579fa41d1521e92558c2d55.png\" alt=\"image1.png\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/post_images\/292\/bc3\/02b\/292bc302b579fa41d1521e92558c2d55.png\"\/><\/div>\n<p>  Recently nullable reference types have become trendy. Meanwhile, the good old nullable value types are still here and actively used. How well do you remember the nuances of working with them? Let&#8217;s jog your memory or test your knowledge by reading this article. Examples of C# and IL code, references to the CLI specification, and CoreCLR code are provided. Let&#8217;s start with an interesting case.  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-416218","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/416218","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=416218"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/416218\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=416218"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=416218"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=416218"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}