【问题标题】:Cast to Func vs new Func?投射到 Func 与新的 Func?
【发布时间】:2014-07-12 04:30:28
【问题描述】:

以下两种说法有区别吗?他们都工作。

if ( ((Func<bool>)(()=>true))() ) { .... };
if ( new Func<bool>(()=>true)()) { .... };

【问题讨论】:

    标签: c# lambda delegates func


    【解决方案1】:

    不,它们都编译为完全相同的 IL。

    更容易看出你是否真的给了 lambda 主体一些依赖于状态的东西 - 否则编译器会为每个 lambda 缓存一个单独的委托实例。但例如:

    using System;
    
    class Test
    {
        bool value = DateTime.Now.Hour == 10;
    
        void Cast()
        {
            if (((Func<bool>)(() => value))())
            {
                Console.WriteLine("Yes");
            }
        }
    
        void New()
        {
            if (new Func<bool>(() => value)())
            {
                Console.WriteLine("Yes");
            }
        }
    
        static void Main()
        {
            new Test().Cast();
            new Test().New();
        }
    }
    

    现在Cast 的 IL 是:

    .method private hidebysig instance void  Cast() cil managed
    {
      // Code size       39 (0x27)
      .maxstack  2
      .locals init (bool V_0)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldftn      instance bool Test::'<Cast>b__0'()
      IL_0008:  newobj     instance void class [mscorlib]System.Func`1<bool>::.ctor(object,
                                                                                    native int)
      IL_000d:  callvirt   instance !0 class [mscorlib]System.Func`1<bool>::Invoke()
      IL_0012:  ldc.i4.0
      IL_0013:  ceq
      IL_0015:  stloc.0
      IL_0016:  ldloc.0
      IL_0017:  brtrue.s   IL_0026
      IL_0019:  nop
      IL_001a:  ldstr      "Yes"
      IL_001f:  call       void [mscorlib]System.Console::WriteLine(string)
      IL_0024:  nop
      IL_0025:  nop
      IL_0026:  ret
    } // end of method Test::Cast
    

    New 的 IL 是:

    .method private hidebysig instance void  New() cil managed
    {
      // Code size       39 (0x27)
      .maxstack  2
      .locals init (bool V_0)
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldftn      instance bool Test::'<New>b__1'()
      IL_0008:  newobj     instance void class [mscorlib]System.Func`1<bool>::.ctor(object,
                                                                                    native int)
      IL_000d:  callvirt   instance !0 class [mscorlib]System.Func`1<bool>::Invoke()
      IL_0012:  ldc.i4.0
      IL_0013:  ceq
      IL_0015:  stloc.0
      IL_0016:  ldloc.0
      IL_0017:  brtrue.s   IL_0026
      IL_0019:  nop
      IL_001a:  ldstr      "Yes"
      IL_001f:  call       void [mscorlib]System.Console::WriteLine(string)
      IL_0024:  nop
      IL_0025:  nop
      IL_0026:  ret
    } // end of method Test::New
    

    如您所见,除了 ldftn 调用之外,它们是相同的,只是使用了适当的编译器生成的方法。

    【讨论】:

    • 我很好奇为什么编译器不会在这里使用相同的委托实例,因为两个匿名函数都有相同的捕获变量('value')。
    • 为什么if ( (()=&gt;true)() ) 不起作用,需要强制转换?编译器应该能够推断出Func&lt;bool&gt;的类型?
    • @dc7a9163d9:为什么?它可以是 any 没有任何参数的委托类型和 true 可以转换为的返回类型。
    • @ErenErsönmez:可以,但是 C# 编译器基本上不会检查这类事情。检查两个看起来相似的lambda表达式是否实际上是等价的,这将是很多工作,并且没有太多好处。
    猜你喜欢
    • 1970-01-01
    • 2017-06-07
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 2013-10-20
    相关资源
    最近更新 更多