Hal yang Anda lewatkan di sini adalah bahwa kompiler memperpanjang masa hidup x
variabel Anda sampai akhir metode di mana ia didefinisikan - itu hanya sesuatu yang dikompilasi - tetapi hanya melakukannya untuk membangun DEBUG.
Jika Anda mengubah kode sehingga variabel didefinisikan dalam metode terpisah, itu akan berfungsi seperti yang Anda harapkan.
Output dari kode berikut adalah:
False
True
Dan kodenya:
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();
}
}
}
Jadi pada dasarnya pemahaman Anda benar, tetapi Anda tidak tahu bahwa kompiler licik akan membuat variabel Anda tetap hidup sampai setelah Anda menelepon GC.Collect()
- bahkan jika Anda secara eksplisit mengaturnya ke nol!
Seperti yang saya sebutkan di atas, ini hanya terjadi untuk build DEBUG - mungkin sehingga Anda dapat memeriksa nilai-nilai untuk variabel lokal saat debugging ke akhir metode (tapi itu hanya dugaan!).
Kode asli TIDAK berfungsi seperti yang diharapkan untuk rilis build - jadi kode berikut ini menghasilkan false, true
untuk build RELEASE dan false, false
untuk build 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.
}
}
}
Sebagai tambahan: Perhatikan bahwa jika Anda melakukan sesuatu di finalizer untuk kelas yang menyebabkan referensi ke objek yang difinalisasi dapat dijangkau dari root program, maka objek itu TIDAK akan menjadi pengumpulan sampah kecuali dan sampai objek itu tidak lagi direferensikan.
Dengan kata lain, Anda dapat memberikan objek "penundaan eksekusi" melalui finalizer. Ini umumnya dianggap sebagai desain yang buruk!
Misalnya, dalam kode di atas, di mana kita melakukannya _extendMyLifetime = this
di finalizer, kita sedang membuat referensi baru ke objek, jadi sekarang tidak akan dikumpulkan sampah sampai _extendMyLifetime
(dan referensi lainnya) tidak lagi referensi itu.
Person1
? Saya hanya melihatPerson
. Terakhir: lihat docs.microsoft.com/dotnet/csharp/programming-guide/… untuk cara kerja finalizers.