21 Anonymous Methods
21.1. Anonymous method expressions
An anonymous method expression (anonymous-method-expression) defines an anonymous method (anonymous), which evaluates to a specific value that references the method.
L Primary-no-array-creation-expression (basic non-array creation expression:)
...
Anonymous-method-expression (anonymous method expression)
L Anonymous-method-expression:
Delegate anonymous-method-signature opt block (anonymous method expression: Delegate anonymous method signature optional block)
L Anonymous-method-signature:
(Anonymous-method-parameter-list opt) (anonymous method signature: Anonymous method parameter list optional)
L Anonymous-method-parameter-list:
Anonymous-method-parameter
Anonymous-method-parameter-list, Anonymous-method-parameter (anonymous method parameter list: Anonymous method parameter anonymous method parameter list)
L Anonymous-method-parameter:
Parameter-modifieropt type identifier (anonymous method parameter: parameter modifier optional type identifier)
An anonymous method expression is categorized as a value with a specific translation rule (§21.3).
An anonymous method expression defines a new declaration space for parameters, local variables, and constants, and defines a new declaration space for the label (§3.3).
21.2 Anonymous method signature
An optional anonymous method signature (anonymous-method-signature) defines the name and type of the formal parameter for the anonymous method. The parameter scope of the anonymous method is block. Matching its scope contains the name of a local variable, local constant, or parameter of an anonymous method expression (anonymous-method-expression), which is a compile-time error for the name of the anonymous method parameter.
If an anonymous method expression has an anonymous method signature, then a compatible delegate type is limited to a collection of delegate types with the same order (§21.3) of the same parameter type and modifier. If an anonymous method expression does not have an anonymous method signature, then a compatible delegate type is limited to a collection of delegate types that do not have an output parameter.
Note that an anonymous method signature cannot contain an attribute or an array of parameters. However, an anonymous method signature can be compatible with the delegate type whose parameter list contains a parameter array.
21.3 Anonymous Method conversions
The
Anonymous method expression is categorized as an untyped value. An anonymous method expression can be used in a delegate creation expression (§21.3.1). All other legitimate uses of an anonymous method expression depend on the implicit conversion defined here. An
implicit conversion exists from an anonymous method expression that is compatible with any delegate. If D is a delegate type and a is an anonymous method expression, D is compatible with a if the following conditions are met:
L First, the parameter type of D is compatible with a:
N if a does not contain an anonymous method signature, D can have 0 or more arguments of any type. The premise is that D does not have any parameters with an output parameter modifier.
N If a has an anonymous method signature, then D must have the same number of arguments, and each parameter of a must have the same type as the corresponding argument to D, and the ref or out modifier for each parameter on a must match the corresponding parameter of D. Whether the last parameter of D is a parameter array and D is independent of the compatibility of a.
L Second, the return type of D must be compatible with a, and for these rules, the case of a containing any other anonymous method blocks is not considered.
N if D uses void to declare the return type, then any return statement contained in a should not specify an expression.
N if D declares the return type with Type R, then any return statement contained in a must specify an expression that can be implicitly converted (§6.1) to R. Also, the end point of A's block must be unreachable.
There is no other conversion of an anonymous method except for any implicit conversions to a compatible delegate type, even for object types.
The following examples illustrate these rules:
delegate void D (int x);D D1 = delegate {}; OkD D2 = Delegate () {}; Error, signature mismatch d d3 = delegate (long x) {}; Error, signature mismatch d d4 = delegate (int x) {}; OkD d5 = delegate (int x) {return;}; OkD d6 = delegate (int x) {return x;}; Error, the return type does not match delegate void E (out int x); E e1 = delegate {}; Error e has an output parameter e e2 = delegate (out int x) {x = 1;}; OkE E3 = delegate (ref int x) {x = 1;}; Error, signature mismatch delegate int P (params int[] a); P P1 = delegate {}; Error, the end point of the block can be up to P P2 = delegate {return;}; Error, return type mismatch p p3 = delegate {return 1;}; OKP P4 = delegate {return "Hello";}; Error, return type mismatch P P5 = delegate (int[] a) {//Okreturn a[0];}; P P6 = delegate (params int[] a) {//error, with params modifier return a[0]; P P7 = Delegate (int[] a) {///error, return type mismatch if (A.length > 0) return A[0];return "Hello"; Delegate Object Q (params int[] a); Q q1 = delegate (int[] a) {//Okif (A.length > 0) return A[0];return "Hello";
21.3.1 Delegate-creation expression
The delegate creation expression [Delegate-creation-expression (§7.5.10.3)] can be used as an alternative syntax for converting an anonymous method to a delegate type. If an expression that is used as an argument to create an expression is an anonymous method expression, the anonymous method converts to the given delegate type using the implicit conversion rules defined above. For example, if D is a delegate type, then an expression
New D (Delegate {Console.WriteLine ("Hello");})
Equivalent to
(D) Delegate {Console.WriteLine ("Hello");}
21.4 anonymous method blocks
The block of an anonymous method expression follows these rules:
L If an anonymous method contains a signature, the parameters specified in the signature are valid within the block. If an anonymous method does not have a signature, it can be converted to a delegate type with a parameter (§21.3), but the parameter is inaccessible within the block.
In addition to the ref and out parameters (if any) specified in the closest enclosing anonymous method signature, accessing the ref or out parameter for the block results in a compile-time error.
When the type of this is a struct type, access to this will result in a compile-time error for the block. This is true whether the access is explicit (like this.x) or implicit (like X in members of a struct instance). This rule simply prohibits such access, but does not affect the results of member lookups in the structure.
The block can access the external variables (§21.5) of the anonymous method. When an anonymous method expression is evaluated (§21.6), access to an external variable references an instance of the active variable.
For a block, a goto statement, break statement, or continue statement that contains a block of its target outside the block, or an inline anonymous method, causes a compile-time error.
The return statement within the block returns control from the closest enclosing anonymous method call, rather than from the enclosing function member. The expression specified in the Return statement must be compatible with a delegate type, and the closest anonymous method expression will be converted to the delegate type (§21.3).
The block of execution of an anonymous method, in addition to the calculation and invocation of an anonymous method expression (evaluation and invocation), has no other method, and is not explicitly described in detail. In particular, the compiler can implement anonymous methods by synthesizing one or more named methods or types, and the names of any such synthesized elements must be kept in one place for the compiler's use: The first name must retain two consecutive stroke characters.
21.5 external variables
The scope contains any local variables, value parameters, and parameter arrays of anonymous method expressions, which are called external variables of the anonymous method expression. In an instance function member of a class, the this value is considered a value parameter and is also an external variable of any anonymous method expression contained within a function member
21.5.1 Capturing external variables
When an external variable is referenced by an anonymous method, it can be said that the external variable was captured by an anonymous method (captured). Typically, the lifetime of a local variable is limited to the execution area (§5.1.7) of the program block or statement it is associated with. However, the lifetime of the captured external variable will be extended at least until the delegate referencing the anonymous method can be garbage collected.
Example
Using system;delegate int d (); class test{static D F () {int x = 0;d result = delegate {return ++x;} return result;} static void Main () {D d = F (); Console.WriteLine (d ()); Console.WriteLine (d ()); Console.WriteLine (d ());}}
The local variable x is captured by an anonymous method, and the lifetime of X is extended at least until the delegate returned from F can be garbage collected (here, until the end of the program), since each invocation of an anonymous method operates on the same instance of X, the result of the sample output is:
123
When a local or value parameter is captured by an anonymous method, the local variable and the value parameter are no longer considered to be fixed (fixed) (§18.3), instead it becomes a moveable (movable) variable. Therefore, any unsafe code that obtains the address of the captured external variable must first use the fixed statement to fix the variable.
21.5.2 local variable instantiation
When a program executes to the scope of a variable, the local variable is considered to be instantiated (instantiated). For example, when the following method is called, the local variable is instantiated and initialized three times-once for each iteration in the loop.
static void F () {for (int i = 0; i < 3; i++) {int x = i * 2 + 1; ...}}
However, if you move the declaration of x out of the loop, you will only have one instantiation of the X.
static void F () {int x;for (int i = 0; i < 3; i++) {x = i * 2 + 1; ...}}
In general, we cannot see exactly how often a local variable is instantiated-because the instantiated life is broken up (disjoint), and it is possible that each instantiation will simply use the same storage location. However, when an anonymous method captures a local variable, the effect of instantiation becomes apparent. As an example
Using system;delegate void D (), Class test{static d[] F () {d[] result = new D[3];for (int i = 0; i < 3; i++) {int x = i * 2 + 1;result[i] = delegate {Console.WriteLine (x);};} return result;} static void Main () {foreach (d d in F ()) D ();}}
produces the following output.
135
But if you move the declaration of x outside of the loop
Static d[] F () {d[] result = new D[3];int x;for (int i = 0; i < 3; i++) {x = i * 2 + 1;result[i] = delegate {CONSOLE.W Riteline (x); };} return result;}
The output is as follows.
555
Note that the three delegates created in the new version of F are equivalent according to the equality operator (§21.7). Also, the compiler is allowed (but not required) to optimize the three-time instantiation to a single delegate instance (§21.6).
You can have anonymous method delegates share some captured variables that have other separate instances. For example, if f is changed
Static d[] F () {d[] result = new D[3];int x = 0;for (int i = 0; i < 3; i++) {int y = 0;result[i] = delegate {CONSOLE.W Riteline ("{0} {1}", ++x, ++y); };} return result;}
These three delegates capture the same instance of X, but capture multiple separate instances of Y, so the output is as follows.
1 12 13 1
A separate anonymous method can capture the same instance of an external variable. For example
Using system;delegate void Setter (int value);d elegate int Getter (); class test{static void Main () {int x = 0; Setter s = delegate (int value) {x = value;}; Getter g = delegate {return x;}; S (5); Console.WriteLine (g ()); s (10); Console.WriteLine (g ());}}
Two anonymous methods capture the same instance of the local variable x, and they can "communicate" through the variable. The example output is as follows.
510
21.6 anonymous method calculation
The anonymous method expression run-time evaluation produces a delegate instance that references an anonymous method, and the collection of captured external variables (possibly empty) is active (the time of the evaluation) when it is calculated (active). The anonymous method body executes when a delegate that is generated by an anonymous method expression is called. The code in the method body is executed using an external variable that is captured by the delegate reference.
The delegate invocation list that is generated when the anonymous method is expressed contains a single entry. Both the exact target object and the target method of the delegate are unspecified. It is important to note that the target object of the delegate is null, as well as the this value of the enclosing function member, or the other object is unspecified.
The semantics of the same anonymous method are computed, and if they have a collection of external variables that have the same captured (possibly empty), you can (but not must) return the same delegate instance. The term "semantically identical" is used here, meaning that the execution period of the anonymous method in all cases produces the same effect given the same argument. This rule allows the following code optimizations.
Delegate double Function (double x); class test{static double[] Apply (double[] A, Function f) {double[] result = new double[ a.length];for (int i = 0; i < a.length; i++) result[i] = f (a[i]); return result; static void F (double[] A, double[] b) {a = Apply (A, delegate (double x) {return Math.sin (x);}); b = Apply (b, delegate (double y) {return Math.sin (y);}); ...}
}
Because two anonymous method delegates have the same set of captured external variables (both empty) and because the anonymous method is semantically identical, the compiler is allowed to produce a delegate that references the same target method. In fact, this allows the compiler to return the same delegate instance from two anonymous method expressions.
(To be continued)
The above is the content of C # 2.0 specification (anonymous method) (a), more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!