Здесь вам не хватает того, что компилятор продлевает время жизни вашей переменной x
до конца метода, в котором она определена - это просто то, что делает компилятор - , но он только делает этодля сборки DEBUG.
Если вы измените код так, чтобы переменная определялась в отдельном методе, он будет работать так, как вы ожидаете.
Вывод следующего кода::
False
True
И код:
using System;
namespace ConsoleApp1
{
class Finalizable
{
~Finalizable()
{
_extendMyLifetime = this;
}
public static bool LifetimeExtended => _extendMyLifetime != null;
static Finalizable _extendMyLifetime;
}
class Program
{
public static void Main()
{
test();
Console.WriteLine(Finalizable.LifetimeExtended); // False.
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Finalizable.LifetimeExtended); // True.
}
static void test()
{
new Finalizable();
}
}
}
Таким образом, в основном ваше понимание было правильным, но вы не знали, что хитрый компилятор будет поддерживать вашу переменную до после вы вызвали GC.Collect()
- даже если вы явно установили его в null!
Как я уже отмечал выше, это происходит только для сборки DEBUG - предположительно, так что вы можете проверять значения для локальных переменных, покаотладка до конца метода (но это только предположение!).
Исходный код работает должным образом для сборки выпуска - поэтому следующий код выводит false, true
для сборки RELEASE и false, false
для сборки DEBUG:
using System;
namespace ConsoleApp1
{
class Finalizable
{
~Finalizable()
{
_extendMyLifetime = this;
}
public static bool LifetimeExtended => _extendMyLifetime != null;
static Finalizable _extendMyLifetime;
}
class Program
{
public static void Main()
{
new Finalizable();
Console.WriteLine(Finalizable.LifetimeExtended); // False.
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine(Finalizable.LifetimeExtended); // True iff RELEASE build.
}
}
}
В качестве дополнения: обратите внимание, что если вы сделаете что-то в финализаторе для класса, который заставит ссылку на финализируемый объект быть достижимой из корня программы, то этот объект НЕ будет собираться мусором до тех пор, пока этот объект не станетссылка более длинная.
Другими словами, вы можете дать объекту «отсрочку исполнения» через финализатор. Обычно это считается плохим дизайном!
Например, в приведенном выше коде, где мы делаем _extendMyLifetime = this
в финализаторе, мы создаем новую ссылку на объект, поэтому он не будеттеперь собирать мусор, пока _extendMyLifetime
(и любая другая ссылка) больше не ссылается на него.