Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 委托是否比类更轻?_C#_Delegates_Clr_Internals_Il - Fatal编程技术网

C# 委托是否比类更轻?

C# 委托是否比类更轻?,c#,delegates,clr,internals,il,C#,Delegates,Clr,Internals,Il,我试图分解一个C#创建的可执行文件,但没有得出结论。我想知道的是,对于CLR c#,委托是真正的特殊实体还是仅仅是一个编译器 我问这个问题是因为我正在实现一种编译成C#的语言,对我来说,将匿名函数编译为类比作为委托有趣得多。但我不想使用一种我以后会后悔的设计,因为它们可能会占用更多的内存(我认为Java的PermGen是我提问的基础,尽管我知道CLR没有这种东西) 谢谢大家! --编辑 更清楚一点,我想知道以下两者之间是否有(以及有什么)区别: void Main() { Func<

我试图分解一个C#创建的可执行文件,但没有得出结论。我想知道的是,对于CLR c#,委托是真正的特殊实体还是仅仅是一个编译器

我问这个问题是因为我正在实现一种编译成C#的语言,对我来说,将匿名函数编译为类比作为委托有趣得多。但我不想使用一种我以后会后悔的设计,因为它们可能会占用更多的内存(我认为Java的PermGen是我提问的基础,尽管我知道CLR没有这种东西)

谢谢大家!

--编辑

更清楚一点,我想知道以下两者之间是否有(以及有什么)区别:

void Main()
{
    Func<int, int, int> add = delegate(int a, int b) {return a + b;};
}
--编辑

我认为这两者之间可能有很大的区别:

class Program
{
    static int add(int a, int b)
    {
        return a + b;
    }

    static void Main()
    {
        Func<int, int, int> add = Program.add;
    }
}
不过,我在某处读到,语法
Func add=Program.add
只是
Func add=delegate(inta,intb){return Program.add;}的一个糖。但我真的不知道这是不是真的。

我还可以看到,C#编译器已经缓存了所有这些实例,因此它们只构造一次。不过,我可以用我的编译器做同样的事情。

两者之间似乎没有什么区别,上面的代码段实际上被编译成了与下面代码段几乎相同的东西。

委托是类。NET编译器为每个委托创建一个类型,代码必须实例化一个委托


在任何情况下,性能上的差异都可以忽略不计,除非您正在编写一个非常罕见的应用程序,其中每一纳秒都很重要。

我很惊讶您无法通过分解可执行文件得出结论。让我们来看一件非常简单的事情:

        using System;

        class A
        {
          int _x;

          public A(int x)
          {
            _x = x;
          }

          public void Print(int y)
          {
            Console.WriteLine(_x + y);
          }
        }

        interface IPseudoDelegateVoidInt
        {
          void Call(int y);
        }


        class PseudoDelegateAPrint : IPseudoDelegateVoidInt
        {
          A _target;
          public PseudoDelegateAPrint(A target)
          {
            _target = target;
          }

          public void Call(int y)
          {
            _target.Print(y);
          }
        }



        class Program
        {
          delegate void RealVoidIntDelegate(int x);
          static void Main()
          {
            A a = new A(5);
            IPseudoDelegateVoidInt pdelegate = new PseudoDelegateAPrint(a);
            RealVoidIntDelegate rdelegate = new RealVoidIntDelegate(a.Print);
            pdelegate.Call(2);
            rdelegate(2);
          }
        }
如果我们把它拆开,我们会得到

        //  Microsoft (R) .NET Framework IL Disassembler.  Version 4.0.30319.1
        //  Copyright (c) Microsoft Corporation.  All rights reserved.



        // Metadata version: v4.0.30319
        .assembly extern mscorlib
        {
          .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
          .ver 4:0:0:0
        }
        .assembly del
        {
          .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
          .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                                     63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
          .hash algorithm 0x00008004
          .ver 0:0:0:0
        }
        .module del.exe
        // MVID: {87A2A843-A5F2-4D40-A96D-9940579DE26E}
        .imagebase 0x00400000
        .file alignment 0x00000200
        .stackreserve 0x00100000
        .subsystem 0x0003       // WINDOWS_CUI
        .corflags 0x00000001    //  ILONLY
        // Image base: 0x0000000000B60000


        // =============== CLASS MEMBERS DECLARATION ===================

        .class private auto ansi beforefieldinit A
               extends [mscorlib]System.Object
        {
          .field private int32 _x
          .method public hidebysig specialname rtspecialname 
                  instance void  .ctor(int32 x) cil managed
          {
            // Code size       17 (0x11)
            .maxstack  8
            IL_0000:  ldarg.0
            IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
            IL_0006:  nop
            IL_0007:  nop
            IL_0008:  ldarg.0
            IL_0009:  ldarg.1
            IL_000a:  stfld      int32 A::_x
            IL_000f:  nop
            IL_0010:  ret
          } // end of method A::.ctor

          .method public hidebysig instance void 
                  Print(int32 y) cil managed
          {
            // Code size       16 (0x10)
            .maxstack  8
            IL_0000:  nop
            IL_0001:  ldarg.0
            IL_0002:  ldfld      int32 A::_x
            IL_0007:  ldarg.1
            IL_0008:  add
            IL_0009:  call       void [mscorlib]System.Console::WriteLine(int32)
            IL_000e:  nop
            IL_000f:  ret
          } // end of method A::Print

        } // end of class A

        .class interface private abstract auto ansi IPseudoDelegateVoidInt
        {
          .method public hidebysig newslot abstract virtual 
                  instance void  Call(int32 y) cil managed
          {
          } // end of method IPseudoDelegateVoidInt::Call

        } // end of class IPseudoDelegateVoidInt

        .class private auto ansi beforefieldinit PseudoDelegateAPrint
               extends [mscorlib]System.Object
               implements IPseudoDelegateVoidInt
        {
          .field private class A _target
          .method public hidebysig specialname rtspecialname 
                  instance void  .ctor(class A target) cil managed
          {
            // Code size       17 (0x11)
            .maxstack  8
            IL_0000:  ldarg.0
            IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
            IL_0006:  nop
            IL_0007:  nop
            IL_0008:  ldarg.0
            IL_0009:  ldarg.1
            IL_000a:  stfld      class A PseudoDelegateAPrint::_target
            IL_000f:  nop
            IL_0010:  ret
          } // end of method PseudoDelegateAPrint::.ctor

          .method public hidebysig newslot virtual final 
                  instance void  Call(int32 y) cil managed
          {
            // Code size       15 (0xf)
            .maxstack  8
            IL_0000:  nop
            IL_0001:  ldarg.0
            IL_0002:  ldfld      class A PseudoDelegateAPrint::_target
            IL_0007:  ldarg.1
            IL_0008:  callvirt   instance void A::Print(int32)
            IL_000d:  nop
            IL_000e:  ret
          } // end of method PseudoDelegateAPrint::Call

        } // end of class PseudoDelegateAPrint

        .class private auto ansi beforefieldinit Program
               extends [mscorlib]System.Object
        {
          .class auto ansi sealed nested private RealVoidIntDelegate
                 extends [mscorlib]System.MulticastDelegate
          {
            .method public hidebysig specialname rtspecialname 
                    instance void  .ctor(object 'object',
                                         native int 'method') runtime managed
            {
            } // end of method RealVoidIntDelegate::.ctor

            .method public hidebysig newslot virtual 
                    instance void  Invoke(int32 x) runtime managed
            {
            } // end of method RealVoidIntDelegate::Invoke

            .method public hidebysig newslot virtual 
                    instance class [mscorlib]System.IAsyncResult 
                    BeginInvoke(int32 x,
                                class [mscorlib]System.AsyncCallback callback,
                                object 'object') runtime managed
            {
            } // end of method RealVoidIntDelegate::BeginInvoke

            .method public hidebysig newslot virtual 
                    instance void  EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
            {
            } // end of method RealVoidIntDelegate::EndInvoke

          } // end of class RealVoidIntDelegate

          .method private hidebysig static void  Main() cil managed
          {
            .entrypoint
            // Code size       45 (0x2d)
            .maxstack  3
            .locals init (class A V_0,
                     class IPseudoDelegateVoidInt V_1,
                     class Program/RealVoidIntDelegate V_2)
            IL_0000:  nop
            IL_0001:  ldc.i4.5
            IL_0002:  newobj     instance void A::.ctor(int32)
            IL_0007:  stloc.0
            IL_0008:  ldloc.0
            IL_0009:  newobj     instance void PseudoDelegateAPrint::.ctor(class A)
            IL_000e:  stloc.1
            IL_000f:  ldloc.0
            IL_0010:  ldftn      instance void A::Print(int32)
            IL_0016:  newobj     instance void Program/RealVoidIntDelegate::.ctor(object,
                                                                                  native int)
            IL_001b:  stloc.2
            IL_001c:  ldloc.1
            IL_001d:  ldc.i4.2
            IL_001e:  callvirt   instance void IPseudoDelegateVoidInt::Call(int32)
            IL_0023:  nop
            IL_0024:  ldloc.2
            IL_0025:  ldc.i4.2
            IL_0026:  callvirt   instance void Program/RealVoidIntDelegate::Invoke(int32)
            IL_002b:  nop
            IL_002c:  ret
          } // end of method Program::Main

          .method public hidebysig specialname rtspecialname 
                  instance void  .ctor() cil managed
          {
            // Code size       7 (0x7)
            .maxstack  8
            IL_0000:  ldarg.0
            IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
            IL_0006:  ret
          } // end of method Program::.ctor

        } // end of class Program


        // =============================================================

        // *********** DISASSEMBLY COMPLETE ***********************
        // WARNING: Created Win32 resource file C:\Users\logan\del.res
如您所见,RealVoidIntDelegate变成了“仅仅”另一个类。他们称它为
Invoke
,而不是
Call
,他们没有使用接口,但没有涉及特殊的指令,这是相同的基本思想


为了详细说明“轻量级”的概念,委托并不比类轻,因为给定的委托是一个类。特别是在函数文字语法的情况下,它们的重量实在是太轻了。然而,对于“使用这些参数调用此对象上的此方法”案例,在编译到C#时,调用和创建给定的委托可能比生成的委托要轻。

这里没有什么神秘之处。通灵乔恩·斯基特

如果您看一下的6.5.3,您将看到编译器如何处理匿名委托的几个示例。简要概述:

如果匿名方法未捕获外部变量,
然后可以将其创建为封闭类型上的静态方法

如果匿名方法引用封闭类型的成员,例如
this.x

然后可以将其创建为封闭类型上的实例方法

如果匿名方法捕获局部变量,
然后可以在封闭类型中创建嵌套类型,实例变量与捕获的变量匹配,实例方法与委托类型匹配


最后一个示例更复杂,只是更容易查看代码。看看你自己,我想它会消除所有的猜测。

除了元数据,一旦一切都得到了解决,就真的没有类了 JIT编译。对象的运行时表示是一个大字节数组 足够存储类的所有字段和 它是基类,加上一个存储 哈希代码、数字类型标识符和指向共享 保存虚拟函数重写地址的v表

委托是一个对象,其类派生自System.delegate。它存储对象和函数指针对的数组

匿名函数是没有名称的函数。然而,它们也是 通常与名为闭包的对象关联,该对象包含在创建指向匿名函数的“匿名委托”的包含方法中定义的所有参数和局部变量。(实际上,它通常只包含那些实际访问的变量)

在任何情况下,将堆栈变量移动到堆中都允许匿名委托在其定义的堆栈框架之外活动

将匿名函数与其闭包相关联的最简单方法是使其成为编译器生成的闭包类的方法

因此,如果您有词汇闭包,您必须(至少在某些情况下)使用类来实现匿名函数

如果没有词法闭包,那么可以将“匿名函数”作为 具有编译器生成名称的常规函数,位于声明该函数的方法旁边。在语言支持词法闭包的情况下,这也是一个有用的优化,但不需要


一般来说,如果没有闭包支持,匿名函数是没有用的,所以如果没有闭包支持,我不会在您的语言中包含它们。

是的,我承认我是一个IL新手。我尝试使用ILDasm,它给了我这样的输出://000043:IntOper add1=delegate(intx,inty);但我确信我选择了错误的拆卸选项;)无论如何,谢谢你的详细回答!但是看看你的拆卸,它引起了我的注意。似乎不是为每个匿名函数创建一个类,而是仅为委托类型declarationRight创建一个类。这就是糖分的来源。在C++/CLI中,您实际上会说
gcnewrealvoidintdelegate(a,&a::Print)
,这可能是
        using System;

        class A
        {
          int _x;

          public A(int x)
          {
            _x = x;
          }

          public void Print(int y)
          {
            Console.WriteLine(_x + y);
          }
        }

        interface IPseudoDelegateVoidInt
        {
          void Call(int y);
        }


        class PseudoDelegateAPrint : IPseudoDelegateVoidInt
        {
          A _target;
          public PseudoDelegateAPrint(A target)
          {
            _target = target;
          }

          public void Call(int y)
          {
            _target.Print(y);
          }
        }



        class Program
        {
          delegate void RealVoidIntDelegate(int x);
          static void Main()
          {
            A a = new A(5);
            IPseudoDelegateVoidInt pdelegate = new PseudoDelegateAPrint(a);
            RealVoidIntDelegate rdelegate = new RealVoidIntDelegate(a.Print);
            pdelegate.Call(2);
            rdelegate(2);
          }
        }
        //  Microsoft (R) .NET Framework IL Disassembler.  Version 4.0.30319.1
        //  Copyright (c) Microsoft Corporation.  All rights reserved.



        // Metadata version: v4.0.30319
        .assembly extern mscorlib
        {
          .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
          .ver 4:0:0:0
        }
        .assembly del
        {
          .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
          .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                                     63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
          .hash algorithm 0x00008004
          .ver 0:0:0:0
        }
        .module del.exe
        // MVID: {87A2A843-A5F2-4D40-A96D-9940579DE26E}
        .imagebase 0x00400000
        .file alignment 0x00000200
        .stackreserve 0x00100000
        .subsystem 0x0003       // WINDOWS_CUI
        .corflags 0x00000001    //  ILONLY
        // Image base: 0x0000000000B60000


        // =============== CLASS MEMBERS DECLARATION ===================

        .class private auto ansi beforefieldinit A
               extends [mscorlib]System.Object
        {
          .field private int32 _x
          .method public hidebysig specialname rtspecialname 
                  instance void  .ctor(int32 x) cil managed
          {
            // Code size       17 (0x11)
            .maxstack  8
            IL_0000:  ldarg.0
            IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
            IL_0006:  nop
            IL_0007:  nop
            IL_0008:  ldarg.0
            IL_0009:  ldarg.1
            IL_000a:  stfld      int32 A::_x
            IL_000f:  nop
            IL_0010:  ret
          } // end of method A::.ctor

          .method public hidebysig instance void 
                  Print(int32 y) cil managed
          {
            // Code size       16 (0x10)
            .maxstack  8
            IL_0000:  nop
            IL_0001:  ldarg.0
            IL_0002:  ldfld      int32 A::_x
            IL_0007:  ldarg.1
            IL_0008:  add
            IL_0009:  call       void [mscorlib]System.Console::WriteLine(int32)
            IL_000e:  nop
            IL_000f:  ret
          } // end of method A::Print

        } // end of class A

        .class interface private abstract auto ansi IPseudoDelegateVoidInt
        {
          .method public hidebysig newslot abstract virtual 
                  instance void  Call(int32 y) cil managed
          {
          } // end of method IPseudoDelegateVoidInt::Call

        } // end of class IPseudoDelegateVoidInt

        .class private auto ansi beforefieldinit PseudoDelegateAPrint
               extends [mscorlib]System.Object
               implements IPseudoDelegateVoidInt
        {
          .field private class A _target
          .method public hidebysig specialname rtspecialname 
                  instance void  .ctor(class A target) cil managed
          {
            // Code size       17 (0x11)
            .maxstack  8
            IL_0000:  ldarg.0
            IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
            IL_0006:  nop
            IL_0007:  nop
            IL_0008:  ldarg.0
            IL_0009:  ldarg.1
            IL_000a:  stfld      class A PseudoDelegateAPrint::_target
            IL_000f:  nop
            IL_0010:  ret
          } // end of method PseudoDelegateAPrint::.ctor

          .method public hidebysig newslot virtual final 
                  instance void  Call(int32 y) cil managed
          {
            // Code size       15 (0xf)
            .maxstack  8
            IL_0000:  nop
            IL_0001:  ldarg.0
            IL_0002:  ldfld      class A PseudoDelegateAPrint::_target
            IL_0007:  ldarg.1
            IL_0008:  callvirt   instance void A::Print(int32)
            IL_000d:  nop
            IL_000e:  ret
          } // end of method PseudoDelegateAPrint::Call

        } // end of class PseudoDelegateAPrint

        .class private auto ansi beforefieldinit Program
               extends [mscorlib]System.Object
        {
          .class auto ansi sealed nested private RealVoidIntDelegate
                 extends [mscorlib]System.MulticastDelegate
          {
            .method public hidebysig specialname rtspecialname 
                    instance void  .ctor(object 'object',
                                         native int 'method') runtime managed
            {
            } // end of method RealVoidIntDelegate::.ctor

            .method public hidebysig newslot virtual 
                    instance void  Invoke(int32 x) runtime managed
            {
            } // end of method RealVoidIntDelegate::Invoke

            .method public hidebysig newslot virtual 
                    instance class [mscorlib]System.IAsyncResult 
                    BeginInvoke(int32 x,
                                class [mscorlib]System.AsyncCallback callback,
                                object 'object') runtime managed
            {
            } // end of method RealVoidIntDelegate::BeginInvoke

            .method public hidebysig newslot virtual 
                    instance void  EndInvoke(class [mscorlib]System.IAsyncResult result) runtime managed
            {
            } // end of method RealVoidIntDelegate::EndInvoke

          } // end of class RealVoidIntDelegate

          .method private hidebysig static void  Main() cil managed
          {
            .entrypoint
            // Code size       45 (0x2d)
            .maxstack  3
            .locals init (class A V_0,
                     class IPseudoDelegateVoidInt V_1,
                     class Program/RealVoidIntDelegate V_2)
            IL_0000:  nop
            IL_0001:  ldc.i4.5
            IL_0002:  newobj     instance void A::.ctor(int32)
            IL_0007:  stloc.0
            IL_0008:  ldloc.0
            IL_0009:  newobj     instance void PseudoDelegateAPrint::.ctor(class A)
            IL_000e:  stloc.1
            IL_000f:  ldloc.0
            IL_0010:  ldftn      instance void A::Print(int32)
            IL_0016:  newobj     instance void Program/RealVoidIntDelegate::.ctor(object,
                                                                                  native int)
            IL_001b:  stloc.2
            IL_001c:  ldloc.1
            IL_001d:  ldc.i4.2
            IL_001e:  callvirt   instance void IPseudoDelegateVoidInt::Call(int32)
            IL_0023:  nop
            IL_0024:  ldloc.2
            IL_0025:  ldc.i4.2
            IL_0026:  callvirt   instance void Program/RealVoidIntDelegate::Invoke(int32)
            IL_002b:  nop
            IL_002c:  ret
          } // end of method Program::Main

          .method public hidebysig specialname rtspecialname 
                  instance void  .ctor() cil managed
          {
            // Code size       7 (0x7)
            .maxstack  8
            IL_0000:  ldarg.0
            IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
            IL_0006:  ret
          } // end of method Program::.ctor

        } // end of class Program


        // =============================================================

        // *********** DISASSEMBLY COMPLETE ***********************
        // WARNING: Created Win32 resource file C:\Users\logan\del.res