local variable declaration with 'is' keyword VS 'as' keyword performance difference

Viewed 64
object obj = "Hello";

// is keyword
if (obj is string str1)
{
   Console.WriteLine(str1);
}

// as keyword
string str2 = obj as string;
if (str2 != null)
{
   Console.WriteLine(str2);
}

In the code above, the local variable is declared with the 'is' keyword, but is there any difference in performance with the 'as' keyword?

I wonder if there is a performance difference related to casting and null checking. (Aside from local scope differences of str1 and str2 variables)

2 Answers

The two code samples are absolutely 100% identical; we can test this by looking at the IL, which can be done in many ways, but the most convenient for ad-hoc things is https://sharplab.io/

Consider:

using System;
public class C {
    object obj = "Hello";
    public void ViaIsWithCapture()
    {
        // is keyword
        if (obj is string str1)
        {
           Console.WriteLine(str1);
        }
    }
    public void ViaAsThenNullTest()
    {
        // as keyword
        string str2 = obj as string;
        if (str2 != null)
        {
           Console.WriteLine(str2);
        }
    }
}

We can run this through sharplab.io like this, and if you look on the right, the IL for both versions works out identical:

    .method public hidebysig 
        instance void ViaIsWithCapture () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 22 (0x16)
        .maxstack 1
        .locals init (
            [0] string str1
        )

        IL_0000: ldarg.0
        IL_0001: ldfld object C::obj
        IL_0006: isinst [System.Private.CoreLib]System.String
        IL_000b: stloc.0
        IL_000c: ldloc.0
        IL_000d: brfalse.s IL_0015

        IL_000f: ldloc.0
        IL_0010: call void [System.Console]System.Console::WriteLine(string)

        IL_0015: ret
    } // end of method C::ViaIsWithCapture

vs

    .method public hidebysig 
        instance void ViaAsThenNullTest () cil managed 
    {
        // Method begins at RVA 0x2074
        // Code size 22 (0x16)
        .maxstack 1
        .locals init (
            [0] string str2
        )

        IL_0000: ldarg.0
        IL_0001: ldfld object C::obj
        IL_0006: isinst [System.Private.CoreLib]System.String
        IL_000b: stloc.0
        IL_000c: ldloc.0
        IL_000d: brfalse.s IL_0015

        IL_000f: ldloc.0
        IL_0010: call void [System.Console]System.Console::WriteLine(string)

        IL_0015: ret
    } // end of method C::ViaAsThenNullTest

This code is better:

string str2 = obj as string;
if (str2 != null)
  {
    Console.WriteLine(str2);
  }

CLR is checking this once while the first one is doing two times, first with IS operator and later in typecasting, which is obviously an overhead.

Related