最近都是想到什么干什么,今晚突然感兴趣委托怎么底层实现的,,看完大佬的解说,再结合自己看源码后的一些总结。不求甚解。
关于delegate关键字 1 2 3 4 5 6 7 8 9 delegate void CustomAction () ;public class C { CustomAction action; public void A () {} void B () { action= } }
delegate说为语法糖也不为过,上行代码相当于帮我们创建了一个继承于MulticastDelegate的类(MulticastDelegate继承于Delegate),这就是为什么我们可以将声明的委托当作类来实例化,如下文
1 2 action=new CustomAction(A);
通过SharpLab查看反编译出的IL码可以看到确实如此
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 .class private auto ansi sealed CustomAction extends [mscorlib]System.MulticastDelegate { .method public hidebysig specialname rtspecialname instance void .ctor ( object 'object' , native int 'method' ) runtime managed { } .method public hidebysig newslot virtual instance void Invoke () runtime managed { } .method public hidebysig newslot virtual instance class [mscorlib ]System.IAsyncResult BeginInvoke ( class [mscorlib ]System.AsyncCallback callback , object 'object ' ) runtime managed { } .method public hidebysig newslot virtual instance void EndInvoke ( class [mscorlib]System.IAsyncResult result ) runtime managed { } }
c#捕获变量和闭包
我们把在Lambda表达式(或匿名方法)中所引用的外部变量称为捕获变量 。
“闭包” in wikipedia:
在计算机科学 中,闭包 (英语:Closure),又称词法闭包 (Lexical Closure)或函数闭包 (function closures),是在支持头等函数 的编程语言中实现词法 绑定 的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量 (该函数内部绑定的符号),也要包括自由变量 (在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。
c#中通常通过生成类来实现捕获变量。通常有三种情形:
未捕获任何变量
捕获实例字段
捕获外部临时变量或外部参数
从反编译里看看c#编译器是如何处理的
未捕获任何变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 delegate int CustomAction (int a ) ;public class C { CustomAction action; void B () { action=(para)=>1 ; } } 反编译码 internal delegate int CustomAction (int a ) ; public class C { [Serializable ] [CompilerGenerated ] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static CustomAction <>9 __2_0; internal int <B>b__2_0(int para) { return 1 ; } } [Nullable(1) ] private CustomAction action; private int instanceProperty = 2 ; private void B () { action = <>c.<>9 __2_0 ?? (<>c.<>9 __2_0 = new CustomAction(<>c.<>9. <B>b__2_0)); } } 创建了一个私有密封嵌套类里的静态方法。
捕获实例字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 delegate int CustomAction (int a ) ;public class C { CustomAction action; int instanceProperty=2 ; void B () { action=(para)=> { instanceProperty=3 ; return instanceProperty; }; } } 反编译码 internal delegate int CustomAction (int a ) ;public class C { [Nullable(1) ] private CustomAction action; private int instanceProperty = 2 ; private void B () { action = new CustomAction(<B>b__2_0); } [CompilerGenerated ] private int <B>b__2_0(int para) { instanceProperty = 3 ; return instanceProperty; } } 创建了一个实例方法
捕获外部临时变量或外部参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 delegate int CustomAction (int a ) ;public class C { CustomAction action; void B () { int a; action=(para)=> { a=2 ; return a; }; } } 反编译码 internal delegate int CustomAction (int a ) ; public class C { [CompilerGenerated ] private sealed class <>c__DisplayClass1_0 { public int a; internal int <B>b__0(int para) { a = 2 ; return a; } } [Nullable(1) ] private CustomAction action; private void B () { <>c__DisplayClass1_0 @object = new <>c__DisplayClass1_0(); action = new CustomAction(@object.<B>b__0); } } 创建了一个私有密封嵌套类,储存上下文信息,如果同时要捕获实例字段,则其嵌套类会储存该实例对象指针。