使用 'is' 关键字的局部变量声明 VS 'as' 关键字的性能差异

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

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);
}

在上面的代码中,局部变量是用'is'关键字声明的,但是用'as'关键字在性能上有什么区别吗?

我想知道是否存在与转换和空值检查相关的性能差异。 (除了 str1 和 str2 变量的局部范围差异)

这段代码更好:

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

CLR 检查一次,而第一个检查两次,第一次使用 IS 运算符,然后进行类型转换,这显然是一种开销。

两个代码示例绝对100%相同;我们可以通过查看 IL 来测试这一点,这可以通过多种方式完成,但最方便的是 https://sharplab.io/

考虑:

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);
        }
    }
}

我们可以 运行 通过 sharplab.io like this,如果你看右边,两个版本的 IL 相同:

    .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

    .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