21.7 Delegate instance equality
The following rules apply to results produced by the equality operator (§7.9.8) and the object.Equals method of anonymous method delegate instances.
l When delegate instances result from evaluation of semantically identical anonymous method expressions with the same set of captured external variables, they are said to be equal (but are not required to be).
l When delegate instances are represented by anonymous method expressions with different semantics, or with different sets of captured external variables, they are never equal.
21.8 Explicit assignment
The explicit assignment status of anonymous method parameters is the same as that of named methods. That is, reference parameters and value parameters are explicitly assigned initial values, while output parameters do not need to be assigned initial values. Also, output parameters must be explicitly assigned before the anonymous method returns normally (§5.1.6).
When control is transferred to the program block of the anonymous method expression, the explicit assignment state of the external variable v is the same as the explicit assignment state of v before the anonymous method expression. That is, explicit assignments to external variables will be inherited from the anonymous method expression context. Within anonymous method blocks, explicit assignments are deduced as within ordinary blocks (§5.3.3).
The explicit assignment status of variable v after the anonymous method expression is the same as its explicit assignment status before the anonymous method expression.
For example,
delegate bool Filter(int i); void F() { int max; // 错误,max没有明确赋值 Filter f = delegate(int n) { return n < max; } max = 5; DoWork(f); }
will generate a compile-time error because max is not explicitly assigned where the anonymous method is declared. Example
delegate void D(); void F() { int n; D d = delegate { n = 1; }; d(); //错误,n没有明确赋值 Console.WriteLine(n); }
will also generate a compile-time error, because the assignment of n inside the anonymous method has no effect on the explicit assignment state of n outside the anonymous method.
21.9 Method Group Conversion
Similar to the implicit anonymous method conversion described in §21.3, there is also an implicit conversion from a method group (§7.1) to a compatible delegate type Convert.
For a given method group E and delegate type D, if delegate creation expressions of the form new D(E) are allowed (§7.5.10.3 and §20.9.6), then there is an implicit path from E to D Conversion, and the result of the conversion is exactly equivalent to new D(E).
In the following example
using System; using System.Windows.Forms; class AlertDialog { Label message = new Label(); Button okButton = new Button(); Button cancelButton = new Button();` public AlertDialog() { okButton.Click += new EventHandler(OkClick); cancelButton.Click += new EventHandler(CancelClick); ... } void OkClick(object sender, EventArgs e) { ... } void CancelClick(object sender, EventArgs e) { ... } }
the constructor uses new to create two delegate instances. Implicit method group conversions allow this to be simplified to
public AlertDialog() { okButton.Click += OkClick; cancelButton.Click += CancelClick; ... }
As with all other implicit and explicit conversions, conversion operators can be used to explicitly perform a specific conversion. For this purpose, the example
object obj = new EventHandler(myDialog.OkClick);
can be replaced as follows.
object obj = (EventHandler)myDialog.OkClick;
Method combination anonymous method expressions can affect overload resolution (overload resolution), but they do not participate in type inference. See §20.6.4 for more details.
21.10 Implementation Example
This section describes the possible implementation of anonymous methods in the form of standard C# components. The implementation described here is based on the same principles employed by the Microsoft C# compiler, but it is by no means mandatory or the only possible implementation.
The latter part of this section gives several example codes, which contain anonymous methods with different characteristics. For each example, we'll provide a corresponding transformation of the code using a unique standard C# construct. In these examples, the identifier D is assumed to represent the following delegate type.
public delegate void D();
The simplest form of an anonymous method is the one that does not capture external variables.
class Test { static void F() { D d = delegate { Console.WriteLine("test"); }; } }
This code can be converted to a delegate instance that references a static method generated by the compiler, and the code of the anonymous method will be placed into the static method. ,
class Test { static void F() { D d = new D(__Method1); } static void __Method1() { Console.WriteLine("test"); } }
In the following example, the anonymous method references the instance member of this.
class Test { int x; void F() { D d = delegate { Console.WriteLine(x); }; } }
This can be converted to an instance method generated by the compiler that contains anonymous method code.
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); }; } }
该局部变量的生存期现在至少必须延长到匿名方法委托的生存期为止。这可以通过将局部变量“提升(lifting)”为编译器生成的(compiler-generated)类的字段来完成。局部变量的实例化对应于创建一个编译器生成的类的实例,而访问局部变量将对应于访问编译器生成的类实例的一个字段。并且,匿名方法将成为编译器生成类的实例方法。
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); } } }
最后,如下匿名方法将捕获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); }; } } }
在这里,编译器将为每个语句块生成类,在这些语句块中局部变量将被捕获,而在不同块中的局部变量将会有独立的生存期。
__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); } } }
(匿名方法完)
以上就是C# 2.0 Specification(匿名方法)(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!