Единственное, чего вам здесь не хватает, так это того, что компилятор продлевает время жизни вашей 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()
- даже если вы явно установите его в нуль!
Как я отмечал выше, это происходит только для сборки 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
(и любая другая ссылка) больше не ссылается на него.
Person1
? Я вижу толькоPerson
. Последнее: см. Docs.microsoft.com/dotnet/csharp/programming-guide/…, чтобы узнать, как работают финализаторы.