В С# 5 семантика замыкания оператора foreach
(когда переменная итерации "захвачена" или "закрыта" анонимными функциями) была лихо изменена (ссылка на тему в этой теме).
Вопрос: Было ли намерено также изменить это для массивов типов указателей?
Причина, по которой я спрашиваю, заключается в том, что "расширение" оператора foreach
должно быть переписано по техническим причинам (мы не можем использовать свойство Current
для System.Collections.IEnumerator
, поскольку это свойство объявило тип object
, который несовместим с типом указателя) по сравнению с foreach
над другими коллекциями. Соответствующий раздел в Спецификации языка С# "Матрицы указателей" в версии 5.0 говорит, что:
foreach (V v in x) EMBEDDED-STATEMENT
расширяется до:
{
T[,,…,] a = x;
V v;
for (int i0 = a.GetLowerBound(0); i0 <= a.GetUpperBound(0); i0++)
for (int i1 = a.GetLowerBound(1); i1 <= a.GetUpperBound(1); i1++)
…
for (int in = a.GetLowerBound(N); iN <= a.GetUpperBound(n); iN++) {
v = (V)a.GetValue(i0,i1,…,iN);
EMBEDDED-STATEMENT
}
}
Заметим, что объявление V v;
находится за пределами всех циклов for
. Таким образом, кажется, что семантика закрытия по-прежнему является "старым" вкусом С# 4, "переменная цикла повторно используется, переменная цикла является" внешней "по отношению к циклу".
Чтобы понять, о чем я говорю, рассмотрите эту полную программу С# 5:
using System;
using System.Collections.Generic;
static class Program
{
unsafe static void Main()
{
char* zeroCharPointer = null;
char*[] arrayOfPointers =
{ zeroCharPointer, zeroCharPointer + 1, zeroCharPointer + 2, zeroCharPointer + 100, };
var list = new List<Action>();
// foreach through pointer array, capture each foreach variable 'pointer' in a lambda
foreach (var pointer in arrayOfPointers)
list.Add(() => Console.WriteLine("Pointer address is {0:X2}.", (long)pointer));
Console.WriteLine("List complete");
// invoke those delegates
foreach (var act in list)
act();
}
// Possible output:
//
// List complete
// Pointer address is 00.
// Pointer address is 02.
// Pointer address is 04.
// Pointer address is C8.
//
// Or:
//
// List complete
// Pointer address is C8.
// Pointer address is C8.
// Pointer address is C8.
// Pointer address is C8.
}
Итак, каков правильный вывод вышеуказанной программы?