Локальные переменные в C#

393
06 октября 2017, 14:40

Есть следующий код на C# (.NET Core):

using System;
public class LambdaTest {
 public static void Main() {
  MyClass obj = new MyClass(32);
  UnsafeFunc(obj);
  obj.EventCall();
  Console.WriteLine();
  obj.EventCall();
 }
 public static void UnsafeFunc(MyClass obj) {
  int local = 10;
  obj.MyEvent += delegate {
   Console.WriteLine("Unsafe event");
   local++;
   Console.WriteLine("Variable from function: {0}", local);
  };
 }
}
public class MyClassArgs: EventArgs {
 public int Prop {
  get;
  set;
 }
 public MyClassArgs(int arg) {
  Prop = arg;
 }
}
public class MyClass {
 public int ObjProp {
  get;
  set;
 }
 public event EventHandler < MyClassArgs > MyEvent;
 public MyClass(int arg) {
  ObjProp = arg;
 }
 public void EventCall() {
  Console.WriteLine("Event call");
  MyEvent(this, new MyClassArgs(64));
 }
}

Метод UnsafeFunc(MyClass obj) назначает событию obj.MyEvent анонимный метод, который изменяет и выводит локальную переменную local, объявленную в UnsafeFunc(MyClass obj). При первом вызове события выводится значение local: 11. При втором вызове: 12. Но дело в том, что local - локальная переменная метода, т.е. после выполнения метода выделенная ей память вроде как должна очищаться. Тогда как объяснить, что обработчик события имеет доступ к памяти, которая не должна существовать?

Answer 1

В языках программирования, в том числе и в C# есть такое понятие, как замыкание (closure). Смысл его в том, что если в каком-либо методе (назовём его Outer) объявлен анонимный метод (скажем Inner), использующий локальные переменные метода Outer, то ссылки на эти переменные будут живы до тех пор, пока Inner не завершит свою работу, даже если Outer уже завершился.

В вашем случае метод UnsafeFunc уже отработал, но переменная local используется в обработчике события obj.MyEvent, и поэтому ссылка на неё сохраняется сборщиком мусора и после выхода из метода UnsafeFunc.

Фактически в этом случае компилятор создаёт анонимный класс, в поля которого записываются захваченные переменные, а в анонимные методы, захватывающие эти переменные, он передаёт поля этого класса.

READ ALSO
Передача значений в Style WPF

Передача значений в Style WPF

Как передать значения их элемента в стиль, который к нему привязан?

429
Проблема с передвижением объекта С#

Проблема с передвижением объекта С#

Здравствуйте! Я только начал разбираться с C#, хочу нарисовать движущийся кругНаписал такие методы:

293
Newtonsoft json

Newtonsoft json

Добрый вечер

374
XML не работает на андроиде

XML не работает на андроиде

Ни XmlDocument, ни HtmlDocument (из библиотеки HtmlAgilityPack) не хотят нормально работать с html страницейВот вам пример:

362