Страница 227 из 502
<b> }</b>
<b> return sum; // возвратить значение из анонимного метода</b>
<b> };</b>
<b> result = count(3);</b>
<b> Console.WriteLine("Сумма 3 равна " + result);</b>
<b> Console.WriteLine();</b>
<b> result = count (5);</b>
<b> Console.WriteLine("Сумма 5 равна " + result);</b>
<b> }</b>
<b>}</b>
В этом варианте кода суммарное значение возвращается кодовым блоком, связанным с экземпляром делегата count. Обратите внимание на то, что оператор return применяется в анонимном методе таким же образом, как и в именованном методе. Ниже приведен результат выполнения данного кода.
<b>0</b>
<b>1</b>
<b>2</b>
<b>3</b>
<b>Сумма 3 равна 6</b>
<b>0</b>
<b>1</b>
<b>2</b>
<b>3</b>
<b>4</b>
<b>5</b>
<b>Сумма 5 равна 15</b>
Локальная переменная, в область действия которой входит анонимный метод, называется внешней переменной. Такие переменные доступны для использования в анонимном методе. И в этом случае внешняя переменная считается захваченной. Захваченная переменная существует до тех пор, пока захвативший ее делегат не будет собран в "мусор". Поэтому если локальная переменная, которая обычно прекращает свое существование после выхода из кодового блока, используется в анонимном методе, то она продолжает существовать до тех пор, пока не будет уничтожен делегат, ссылающийся на этот метод.
Захват локальной переменной может привести к неожиданным результатам. В качестве примера рассмотрим еще один вариант программы подсчета с суммированием чисел. В данном варианте объект CountIt конструируется и возвращается статическим методом Counter(). Этот объект использует переменную sum, объявленную в охватывающей области действия метода Counter(), а не самого анонимного метода. Поэтому переменная sum захватывается анонимным методом. Метод Counter() вызывается в методе Main() для получения объекта CountIt, а следовательно, переменная sum не уничтожается до самого конца программы.
<b>// Продемонстрировать применение захваченной переменной,</b>
<b>using System;</b>
<b>// Этот делегат возвращает значение типа int</b>
<b>// и принимает аргумент типа int. </b>
<b>delegate int CountIt(int end);</b>
<b>class VarCapture {</b>
<b> static CountIt Counter() {</b>
<b> int sum = 0;</b>
<b> // Здесь подсчитанная сумма сохраняется в переменной sum.</b>
<b> CountIt ctObj = delegate (int end) {</b>
<b> for(int i=0; i <= end; i++) {</b>
<b> Console.WriteLine(i);</b>
<b> sum += i;</b>
<b> }</b>
<b> return sum;</b>
<b> };</b>
<b> return ctObj;</b>
<b> }</b>
<b> static void Main() {</b>
<b> // Получить результат подсчета.</b>
<b> CountIt count = Counter();</b>
<b> int result;</b>
<b> result = count(3);</b>
<b> Console.WriteLine("Сумма 3 равна " + result);</b>
<b> Console.WriteLine();</b>
<b> result = count(5);</b>
<b> Console.WriteLine("Сумма 5 равна " + result);</b>
<b> }</b>
<b>}</b>
Ниже приведен результат выполнения этой программы. Обратите особое внимание на суммарное значение.
<b>0</b>
<b>1</b>
<b>2</b>
<b>3</b>
<b>Сумма 3 равна 6</b>
<b>0</b>
<b>1</b>
<b>2</b>
<b>3</b>
<b>4</b>
<b>5</b>
<b>Сумма 5 равна 21</b>
Как видите, подсчет по-прежнему выполняется как обычно. Но обратите внимание на то, что сумма 5 теперь равна 21, а не 15! Дело в том, что переменная sum захватывается объектом ctObj при его создании в методе Counter(). Это означает, что она продолжает существовать вплоть до уничтожения делегата count при "сборке мусора" в самом конце программы. Следовательно, ее значение не уничтожается после возврата из метода Counter() или при каждом вызове анонимного метода, когда происходит обращение к делегату count в методе Main().