【问题标题】:local variable declaration with 'is' keyword VS 'as' keyword performance difference使用'is'关键字与'as'关键字性能差异的局部变量声明
【发布时间】:2020-07-12 10:10:46
【问题描述】:
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变量的局部范围差异)

【问题讨论】:

  • 很确定它们编译为相同的 IL。你可以尝试在sharplab.io上编译它。
  • 感谢您的回答。这是一个不错的实用程序。比较 IL 时,结果完全一样。
  • 旁注:尽管在这里无关紧要,但您应该更喜欢 is object 而不是 != null - 区别在于 != null 可以调用自定义相等/转换运算符, 可能比简单的空测试开销更大; is object 语法从不调用运算符。

标签: c# performance keyword


【解决方案1】:

这两个代码示例绝对 100% 相同;我们可以通过查看 IL 来测试这一点,这可以通过多种方式完成,但对于 ad-hoc 最方便的是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

【讨论】:

    【解决方案2】:

    这段代码更好:

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

    CLR 会检查一次,而第一个会检查两次,首先是 IS 运算符,然后是类型转换,这显然是一种开销。

    【讨论】:

    • 有趣的是,“显而易见”的事情往往是错误的;在这种情况下,两个版本绝对 100% 相同 - 在此处比较 IL:sharplab.io/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 2014-03-19
    相关资源
    最近更新 更多