Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
13
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

7.15.5.2Создание экземпляров локальных переменных

Считается, что для локальной переменной создается экземпляр, когда выполнение входит в область действия переменной. Например, при вызове следующего метода экземпляр локальной переменной x создается и инициализируется три раза, один раз для каждой итерации цикла.

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

Однако если перенести объявления x за пределы цикла, то экземпляр x будет создаваться только один раз.

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

Если локальная переменная не захвачена, то не существует способа точно отследить, сколько раз создавались ее экземпляры, потому что сроки жизни экземпляров не связаны. Для каждого экземпляра можно просто использовать одно место хранения. Однако когда локальная переменная захватывается анонимной функцией, результат создания экземпляра становится очевидным.

В примере

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(); } }

дает на выходе:

1 3 5

Однако при переносе объявления x за пределы цикла:

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; }

вывод имеет вид:

5 5 5

Если в цикле for объявляется переменная итерации, то сама эта переменная считается объявленной за пределами цикла. Таким образом, если изменить пример, чтобы захватывать саму переменную итерации

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

то будет захвачен только один экземпляр переменной итерации. В этом случае вывод имеет вид

3 3 3

Делегаты анонимных функций могут иметь некоторые общие захваченные переменные и в то же время иметь отдельные экземпляры других переменных. Например, если F изменить на

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; }

то три делегата будут захватывать один экземпляр x, но разные экземпляры y. Вывод будет иметь вид:

1 1 2 1 3 1

Отдельные анонимные функции могут захватывать один экземпляр внешней переменной. В следующем примере:

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()); } }

две анонимные функции захватывают один экземпляр локальной переменной x и поэтому они могут «взаимодействовать» через эту переменную. Вывод в данном примере имеет вид:

5 10

7.15.6Вычисление выражений анонимных функций

Анонимная функция F всегда должна преобразовываться в тип делегата D или тип дерева выражения E либо напрямую, либо с помощью выполнения выражения создания делегата new D(F). Это преобразование определяет результат анонимной функции, как описано в разделе §6.5.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]