Читая Герберта Шилдта, дошел до раздела "Применение внешних переменных в анонимных методах" где в частности сказано:
Захваченная переменная существует до тех пор, пока захвативший ее делегат не будет собран в "мусор".
А как мне в этом можно убедится? В том, что переменная действительно существует после выхода из кодового блока. Отладчик в Visual Studio говорит:
error CS0103: The name 'variable' does not exist in the current context.
Вот пример кода:
class Program
{
delegate void MyDelegate();
static void Main(string[] args)
{
Test();
}
static void Test()
{
int i;
MyDelegate myDelegate = delegate { i = 10; Console.WriteLine(i.ToString()); };
myDelegate();
}
}
Тут переменная i будет жить до сборки мусора.
Ответ
Переменная и область видимости - это понятия уровня языка, а не уровня рантайма.
После IL-компиляции переменная превращается в одну из двух вещей:
- значение в стеке
- поле класса-замыкания
После JIT-компиляции и значения в стеке, и значения полей замыкания могут местами кешироваться еще и в регистрах процессора.
То, что вы хотите проверить - это существование класса-замыкания в куче после того, управление покинуло область видимости локальной переменной. Можно проверить студией, или любым другим отладчиком, позволяющим смотреть содержимое кучи:
static void Main(string[] args)
{
Debugger.Break();
{
string var1 = "somevalue";
Action a = () => { var1 = "newvalue"; };
}
Debugger.Break();
}
после остановки на первом брейке открыть Debug -> Show Diagnostic Tools, и нажать Memory Usage / Take Snapshot.
продолжить выполнение, на втором брейке нажать Take Snapshot еще раз. И сравнить снапшоты:
Видно что и объект замыкания и локальная переменная еще живы, кроме того, в path to root для обоих показывается что они являются локальными переменными метода.
Картина чуть поменяется при запуске в Release не под отладчиком. Следующий код покажет нулевой дифф - оптимизатор просто выбросит все неиспользуемое:
Debugger.Launch();
{
string var1 = "somevalue";
Action a = () => { var1 = "newvalue"; };
}
Debugger.Break();
А вот если вы продлите время жизни Action, то сможете увидеть что объект-замыкание жив, хотя переменная уже недоступна:
static void Main(string[] args)
{
Action a;
Debugger.Launch();
{
string var1 = "somevalue";
a = () => { var1 = "newvalue"; };
}
Debugger.Break();
a();
}
Комментариев нет:
Отправить комментарий