ЗНАЕТЕ ЛИ ВЫ?

Instantiation of local variables



A local variable is considered to be instantiated when execution enters the scope of the variable. For example, when the following method is invoked, the local variable x is instantiated and initialized three times—once for each iteration of the loop.

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

However, moving the declaration of x outside the loop results in a single instantiation of x:

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

When not captured, there is no way to observe exactly how often a local variable is instantiated—because the lifetimes of the instantiations are disjoint, it is possible for each instantation to simply use the same storage location. However, when an anonymous function captures a local variable, the effects of instantiation become apparent.

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] = () => { Console.WriteLine(x); };
}
return result;
}

static void Main() {
foreach (D d in F()) d();
}
}

produces the output:

1
3
5

However, when the declaration of x is moved 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] = () => { Console.WriteLine(x); };
}
return result;
}

the output is:

5
5
5

If a for-loop declares an iteration variable, that variable itself is considered to be declared outside of the loop. Thus, if the example is changed to capture the iteration variable itself:

static D[] F() {
D[] result = new D[3];
for (int i = 0; i < 3; i++) {
result[i] = () => { Console.WriteLine(i); };
}
return result;
}

only one instance of the iteration variable is captured, which produces the output:

3
3
3

It is possible for anonymous function delegates to share some captured variables yet have separate instances of others. For example, if F is changed to

static D[] F() {
D[] result = new D[3];
int x = 0;
for (int i = 0; i < 3; i++) {
int y = 0;
result[i] = () => { Console.WriteLine("{0} {1}", ++x, ++y); };
}
return result;
}

the three delegates capture the same instance of x but separate instances of y, and the output is:

1 1
2 1
3 1

Separate anonymous functions can capture the same instance of an outer variable. In the example:

using System;

delegate void Setter(int value);

delegate int Getter();

class Test
{
static void Main() {
int x = 0;
Setter s = (int value) => { x = value; };
Getter g = () => { return x; };
s(5);
Console.WriteLine(g());
s(10);
Console.WriteLine(g());
}
}

the two anonymous functions capture the same instance of the local variable x, and they can thus “communicate” through that variable. The output of the example is:

5
10

Evaluation of anonymous function expressions

An anonymous function F must always be converted to a delegate type D or an expression tree type E, either directly or through the execution of a delegate creation expression new D(F). This conversion determines the result of the anonymous function, as described in §6.5.

Query expressions

Query expressions provide a language integrated syntax for queries that is similar to relational and hierarchical query languages such as SQL and XQuery.

query-expression:
from-clause query-body

from-clause:
from typeopt identifier in expression

query-body:
query-body-clausesopt select-or-group-clause query-continuationopt

query-body-clauses:
query-body-clause
query-body-clauses query-body-clause

query-body-clause:
from-clause
let-clause
where-clause
join-clause
join-into-clause
orderby-clause

let-clause:
let identifier = expression

where-clause:
where boolean-expression

join-clause:
join typeopt identifier in expression on expression equals expression

join-into-clause:
join typeopt identifier in expression on expression equals expression into identifier

orderby-clause:
orderby orderings

orderings:
ordering
orderings , ordering

ordering:
expression ordering-directionopt

ordering-direction:
ascending
descending

select-or-group-clause:
select-clause
group-clause

select-clause:
select expression

group-clause:
group expression by expression

query-continuation:
into identifier query-body

A query expression begins with a from clause and ends with either a select or group clause. The initial from clause can be followed by zero or more from, let, where, join or orderby clauses. Each from clause is a generator introducing a range variable which ranges over the elements of a sequence. Each let clause introduces a range variable representing a value computed by means of previous range variables. Each where clause is a filter that excludes items from the result. Each join clause compares specified keys of the source sequence with keys of another sequence, yielding matching pairs. Each orderby clause reorders items according to specified criteria.The final select or group clause specifies the shape of the result in terms of the range variables. Finally, an into clause can be used to “splice” queries by treating the results of one query as a generator in a subsequent query.





Последнее изменение этой страницы: 2016-12-14; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.216.79.60 (0.007 с.)