实现实例
这一节将讨论一些标准C#构造中匿名方法的可能的实现。这里描述的实现和Visual C#编译器基于相同的原理,但这并不是必须的实现,而只是一种可能。
本节的最后将给出包含了不同特征的匿名方法的代码实例。对于每个例子,转换得到的相应代码仅使用了标准C#提供的构造。这些例子中,假设标识符D为下面这样的委托类型:
public delegate void D();
最简单的匿名方法是不捕获任何外部变量的匿名方法:
class Test {
static void F() {
D d = delegate { Console.WriteLine("test"); };
}
}
它会被翻译为一个委托实例,它引用了一个编译器产生的静态方法,这个方法中包含了匿名方法中的代码:
class Test {
static void F() {
D d = new D(__Method1);
}
static void __Method1() {
Console.WriteLine("test");
}
}
In the following example, the anonymous method references instance members of this:
下面的例子中,你名方法引用了this的实例成员:
class Test {
int x;
void F() {
D d = delegate { Console.WriteLine(x); };
}
}
This can be translated to a compiler generated instance method containing the code of the anonymous method:
它会被翻译为一个编译器生成的实例方法,该方法包含了匿名方法中的代码:
class Test {
int x;
void F() {
D d = new D(__Method1);
}
void __Method1() {
Console.WriteLine(x);
}
}
In this example, the anonymous method captures a local variable:
在这个例子中,匿名方法捕获了一个局部变量:
class Test {
void F() {
int y = 123;
D d = delegate { Console.WriteLine(y); };
}
}
The lifetime of the local variable must now be extended to at least the lifetime of the anonymous method delegate. This can be achieved by “lifting” the local variable into a field of a compiler generated class. Instantiation of the local variable (§21.5.2) then corresponds to creating an instance of the compiler generated class, and accessing the local variable corresponds to accessing a field in the instance of the compiler generated class. Furthermore, the anonymous method becomes an instance method of the compiler generated class:
局部变量的生存期现在必须扩展为至少持续到匿名方法委托的生存期结束。这可以通过将局部变量“提升”到一个编译器生成的类的域中来完成。局部变量的实例化(见3.5.2)相当于建立编译器生成的类的一个实例,而访问局部变量相当于访问编译器建立的类的这个实例的域。另外,匿名方法变成编译器生成的类的一个实例方法:
class Test {
void F() {
__locals1 = new __Locals1();
__locals1.y = 123;
D d = new D(__locals1.__Method1);
}
class __Locals1 {
public int y;
public void __Method1() {
Console.WriteLine(y);
}
}
}
Finally, the following anonymous method captures this as well as two local variables with different lifetimes:
最后,下面的匿名方法捕获了this和两个具有不同生存期的局部变量:
class Test {
int x;
void F() {
int y = 123;
for (int i = 0; i < 10; i++) {
int z = i * 2;
D d = delegate { Console.WriteLine(x + y + z); };
}
}
}
Here, a compiler generated class is created for each statement block in which locals are captured such that the locals in the different blocks can have independent lifetimes. An instance of __Locals2, the compiler generated class for the inner statement block, contains the local variable z and a field that references an instance of __Locals1. An instance of __Locals1, the compiler generated class for the outer statement block, contains the local variable y and a field that references this of the enclosing function member. With these data structures it is possible to reach all captured outer variables through an instance of __Local2, and the code of the anonymous method can thus be implemented as an instance method of that class.
这里,编译器为每一个捕获了局部变量的语句块分别都生成了一个类。因此,那些在不同的块中所捕获的局部变量具有独立的生存期。编译器为内层语句块建立的类__Locals2的一个实例,包含了局部变量z和一个引用了__Locals1的实例的域。编译器为外层语句块建立的类__Locals1的一个实例,包含了局部变量y和一个引用了函数成员所在类的this的一个域。通过这些数据结构,可以通过__Locals2的一个实例来获得所有捕获的外部变量,而匿名方法中的代码因此被实现为该类的一个实例方法。
class Test {
void F() {
__locals1 = new __Locals1();
__locals1.__this = this;
__locals1.y = 123;
for (int i = 0; i < 10; i++) {
__locals2 = new __Locals2();
__locals2.__locals1 = __locals1;
__locals2.z = i * 2;
D d = new D(__locals2.__Method1);
}
}
class __Locals1 {
public Test __this;
public int y;
}
class __Locals2 {
public __Locals1 __locals1;
public int z;
public void __Method1() {
Console.WriteLine(__locals1.__this.x + __locals1.y + z);
}
}
}