В интересах простоты я буду использовать Dummy
класс (вместо вашего общего A
):
class Dummy
{
public int i = 0;
~Dummy()
{
Console.WriteLine("~Dummy --> " + i);
}
}
Обратите внимание на финализатор , который позволяет нампосмотрите точное время, в которое он будет собран GC.
Теперь рассмотрим эту вспомогательную функцию: она создает новую Dummy d
, затем оборачивает ее в функцию закрытия и возвращаетэто закрытие.
static Func<int> MakeFunc()
{
Dummy d = new Dummy();
Func<int> f = () => {
d.i++;
Console.WriteLine("Func invoked, d.i is now " + d.i);
return d.i;
};
return f;
}
Мы можем назвать это так:
public static void Main()
{
Console.WriteLine("1");
Func<int> f = MakeFunc();
f();
Console.WriteLine("2");
Вывод:
1
Func invoked, d.i is now 1
2
Мы можем форсировать цикл сбора мусора:
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("3");
Вывод:
3
Обратите внимание, что мы еще не видели, как работает финализатор !Dummy
объект все еще жив и удерживается закрытием функции.
Фактически мы можем продолжать вызывать функцию:
f();
Console.WriteLine("4");
Выход:
Func invoked, d.i is now 2
4
Этот экземпляр Dummy
будет завершен, когда мы отбрасываем ссылку и запускаем другой цикл сбора мусора:
f = null;
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("5");
Вывод:
~Dummy --> 2
5
PS: Здесь я использую GC.Collect()
в демонстрационных целях.Как правило, нет необходимости (и нецелесообразно) называть это так в рабочем коде.