最近都是想到什么干什么,今晚突然感兴趣委托怎么底层实现的,,看完大佬的解说,再结合自己看源码后的一些总结。不求甚解。

关于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
{
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor (
object 'object',
native int 'method'
) runtime managed
{
} // end of method CustomAction::.ctor

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

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

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

} // end of class CustomAction

c#捕获变量和闭包

我们把在Lambda表达式(或匿名方法)中所引用的外部变量称为捕获变量

“闭包” in wikipedia:

计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量(该函数内部绑定的符号),也要包括自由变量(在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。

c#中通常通过生成类来实现捕获变量。通常有三种情形:

  1. 未捕获任何变量

  2. 捕获实例字段

  3. 捕获外部临时变量或外部参数

从反编译里看看c#编译器是如何处理的

  1. 未捕获任何变量
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. 捕获实例字段
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. 捕获外部临时变量或外部参数

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

    创建了一个私有密封嵌套类,储存上下文信息,如果同时要捕获实例字段,则其嵌套类会储存该实例对象指针。