C # 2.0 specification (anonymous method) (i)

Source: Internet
Author: User
Tags anonymous empty execution expression modifier sin
21 Anonymous Methods
21.1. Anonymous method expression
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 blocks)

L Anonymous-method-signature:
(Anonymous-method-parameter-list opt) (anonymous method signature: Optional anonymous method argument list)

L Anonymous-method-parameter-list:
Anonymous-method-parameter
Anonymous-method-parameter-list, Anonymous-method-parameter (anonymous method argument 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 transformation rule (§21.3).

Anonymous method expressions define a new declaration space for parameters, local variables, and constants, and a new declaration space is defined for the label (§3.3).



21.2 Anonymous method signature
The optional anonymous method signature (anonymous-method-signature) defines the name and type of the formal parameter for the anonymous method. The parameter scope of an anonymous method is block. Matching the name of a local variable, local constant, or parameter whose scope contains an anonymous method expression (anonymous-method-expression) is a compile-time error for the name of an anonymous method parameter.

If an anonymous method expression has an anonymous method signature, then the compatible delegate type is limited to the collection of delegate types that have the same parameter types and modifiers of the same order (§21.3). If an anonymous method expression does not have an anonymous method signature, then the compatible delegate type is limited to the collection of delegate types that do not have an output parameter.



Note that anonymous method signatures cannot contain attributes or array of parameters. However, an anonymous method signature can be compatible with a delegate type that contains a parameter array in its argument list.



21.3 Anonymous Method conversions
Anonymous method expressions are categorized as a value of no type. 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 true:

L First, the parameter type of D is compatible with a:

N If a does not contain anonymous method signatures, then D can have 0 or more parameters of any type, provided 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, each parameter of a must have the same type as the corresponding parameter of D, and the existence of 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 has nothing to do with the compatibility of a.

L Second, the return type of D must be compatible with a, and for these rules, it does not take into account the case that a contains any other anonymous method blocks.

N if D uses the Void declaration return type, then any return statement contained in a should not specify an expression.

N if D uses type R to declare the return type, 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 block must be not reached.

There is no other conversion of anonymous methods other than any implicit conversion to a compatible delegate type, even for object types.

The following examples illustrate these rules:

delegate void D (int x);

D D1 = delegate {}; Ok
D D2 = Delegate () {}; Error, Signature mismatch
D D3 = delegate (long x) {}; Error, Signature mismatch
D D4 = delegate (int x) {}; Ok
D d5 = delegate (int x) {return;}; Ok
D d6 = delegate (int x) {return x;}; Error, return type mismatch

delegate void E (out int x);

E e1 = delegate {}; Error e has output parameters
E e2 = delegate (out int x) {x = 1;}; Ok
E 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 is up to

P P2 = delegate {return;}; Error, return type mismatch

P P3 = delegate {return 1;}; Ok
P P4 = delegate {return "Hello";}; Error, return type mismatch
P P5 = delegate (int[] a) {//Ok
return 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) {//Ok
if (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 used as an argument for a delegate-creation expression is an anonymous method expression, the anonymous method converts the implicit conversion rule defined above to the given delegate type. 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 argument is inaccessible within the block.

In addition to the ref and out parameters (if any) specified in the closest enclosing anonymous method signature, accessing a ref or out parameter for a block results in a compile-time error.

L 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 (as for X in a member of a struct instance). This rule simply prohibits such access, but does not affect the results of member lookups in the structure.

An L block can access an external variable (§21.5) of an anonymous method. When an anonymous method expression is evaluated (§21.6), access to an external variable will refer to an instance of the active (active) variable.

L A goto statement, a break statement, or a continue statement that contains a block of objects outside a block, or an embedded anonymous method, will cause a compile-time error for the block.

L The return statement within the block returns control from the closest enclosing anonymous method call, not 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).



There are other ways to execute an anonymous method's block, in addition to the calculation and invocation of an anonymous method expression (evaluation and invocation), and are not explicitly described in detail. In particular, the compiler can implement anonymous methods by synthesizing one or more named methods or types, and the name of any such composite element must be kept in one place for use by the compiler: the name must retain two consecutive strokes.

21.5 external variables
A scope contains any local, value, and parameter arrays of anonymous method expressions, all of which are called external variables of an anonymous method expression. In an instance function member of a class, the this value is considered to be a value parameter and it is also an external variable of any anonymous method expression contained within a function member



21.5.1 Capture External variables
When an external variable is referenced by an anonymous method, it can be said that the external variable is captured by the 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 the anonymous method, and the lifetime of X is at least extended until the delegate returned from F can be garbage collected (where this is not satisfied until the end of the program), since each invocation of the anonymous method operates on the same instance of X, the result of the example output is:

1
2
3

When a local variable or a value parameter is captured by an anonymous method, the local variable and the value parameter are no longer considered to be fixed (§18.3) variables, instead they become movable (movable) variables. Therefore, any unsafe code that obtains the address of a captured external variable must first fix the variable with the fixed statement.

21.5.2 local variable instantiation
When a program executes to the scope of a variable, a local variable is considered instantiated (instantiated). For example, when the following method is invoked, the local variable is instantiated and initialized three times-one time for each iteration in the loop.

static void F () {
for (int i = 0; i < 3; i++) {
int x = i * 2 + 1;
...
}
}

However, if the declaration of X is moved out of the loop, only one instantiation of x will occur.

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 once--because the lifetime of the instantiation is torn apart (disjoint), and it is possible that each instantiation uses the same storage location only. However, when an anonymous method captures a local variable, the effect of the instantiation becomes apparent. such as the 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.

1
3
5



But if you move the declaration of x outside 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.WriteLine (x);};
}
return result;
}

Its output is as follows.

5
5
5

Note that the three delegates created in the new version of F are equivalent based on the equality operator (§21.7). Also, allow the compiler (but not the required) to optimize the three-time instantiation to a single delegate instance (§21.6).

You can have the anonymous method delegate share some of the 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.WriteLine ("{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 1
2 1
3 1

A separate anonymous method can capture the same instance of an external variable. For example

Using System;

delegate void Setter (int value);

delegate 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 local variable x, and they can "communicate" through the variable. The sample output is as follows.

5
10

21.6 anonymous method calculation
The run-time computation of the anonymous method expression test produces a delegate instance that references the anonymous method, and the collection of the captured external variables (which may be empty) is active (active) at the time of calculation (the evaluation). When a delegate generated by an anonymous method expression is invoked, the anonymous method body executes. The code in the method body is executed using external variables that are captured by the delegate reference.

The delegate invocation list that is generated by an anonymous method expression contains a single entry. Both the exact target object and the target method for the delegate are unspecified. Special attention is given to whether the target object of the delegate is null, and the this value of the enclosing function member, or other objects are unspecified.

The computation of semantically identical anonymous methods, which, if they carry a collection of external variables with the same capture (which may be empty), can, but do not, 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 for code optimization as follows.

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)



Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.