title: Null coalesce operator implications?
body: <p>A while back I compiled two versions of a code, one using <code>(Nullable&lt;T&gt;)x.GetValueOrDefault(y)</code> and one using <code>(Nullable&lt;T&gt;)x ?? y)</code>.</p>
  
  <p>After decompiling to IL I noticed that the null coalesce operator is transformed into the <code>GetValueOrDefault</code> call.</p>
  
  <p>Since it's a method call to which an expression can be passed that is evaluated before execution of the method, <code>y</code> seems to be always executed.</p>
  
  <p>For example:</p>
  
  <pre><code>using System;
  
  public static class TestClass
  {
      private class SomeDisposable : IDisposable
      {
          public SomeDisposable()
          {
              // Allocate some native resources
          }
  
          private void finalize()
          {
              // Free those resources
          }
  
          ~SomeDisposable()
          {
              finalize();
          }
  
          public void Dispose()
          {
              finalize();
              GC.SuppressFinalize(this);
          }
      }
  
      private struct TestStruct
      {
          public readonly SomeDisposable _someDisposable;
          private readonly int _weirdNumber;
  
          public TestStruct(int weirdNumber)
          {
              _weirdNumber = weirdNumber;
              _someDisposable = new SomeDisposable();
          }
      }
  
      public static void Main()
      {
          TestStruct? local = new TestStruct(0);
  
          TestStruct local2 = local ?? new TestStruct(1);
  
          local2._someDisposable.Dispose();
      }
  }
  </code></pre>
  
  <p>Seems to result into an indisposed object, and probably performance implications too.</p>
  
  <p>First of all, is this true? Or does the JIT or something alike change the actually executed ASM code?</p>
  
  <p>And secondly can someone explain why it has this behavior?</p>
  
  <p><strong>NOTE:</strong> This is just an example, it is not based upon real code, and please refrain from making comments like 'this is bad code'.</p>
  
  <p><strong>IL DASM:</strong><br>
  Okay, when I compiled this with .Net Framework 2.0 it resulted in identical code with calling null coalesce and GetValueOrDefault. With .Net Framework 4.0, it generates these two codes:</p>
  
  <p><strong>GetValueOrDefault:</strong></p>
  
  <pre><code>.method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       19 (0x13)
    .maxstack  2
    .locals init ([0] valuetype [mscorlib]System.Nullable`1&lt;int32&gt; nullableInt,
             [1] int32 nonNullableInt)
    IL_0000:  nop
    IL_0001:  ldloca.s   nullableInt
    IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1&lt;int32&gt;
    IL_0009:  ldloca.s   nullableInt
    IL_000b:  ldc.i4.1
    IL_000c:  call       instance !0 valuetype [mscorlib]System.Nullable`1&lt;int32&gt;::GetValueOrDefault(!0)
    IL_0011:  stloc.1
    IL_0012:  ret
  } // end of method Program::Main
  </code></pre>
  
  <p><strong>Null Coalesce:</strong></p>
  
  <pre><code>.method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       32 (0x20)
    .maxstack  2
    .locals init (valuetype [mscorlib]System.Nullable`1&lt;int32&gt; V_0,
             int32 V_1,
             valuetype [mscorlib]System.Nullable`1&lt;int32&gt; V_2)
    IL_0000:  nop
    IL_0001:  ldloca.s   V_0
    IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1&lt;int32&gt;
    IL_0009:  ldloc.0
    IL_000a:  stloc.2
    IL_000b:  ldloca.s   V_2
    IL_000d:  call       instance bool valuetype [mscorlib]System.Nullable`1&lt;int32&gt;::get_HasValue()
    IL_0012:  brtrue.s   IL_0017
    IL_0014:  ldc.i4.1
    IL_0015:  br.s       IL_001e
    IL_0017:  ldloca.s   V_2
    IL_0019:  call       instance !0 valuetype [mscorlib]System.Nullable`1&lt;int32&gt;::GetValueOrDefault()
    IL_001e:  stloc.1
    IL_001f:  ret
  } // end of method Program::Main
  </code></pre>
  
  <p>As it turns out that this is no longer the case, and that it skips over the <code>GetValueOrDefault</code> call altogether when <code>HasValue</code> returns false.</p>