使用Object Initializer的复活差异

我有这个代码:

本质上我正在尝试演示使用c#终结器并制作一个不能死的对象,我称之为Zombie。 现在,通常这个演示工作得很好,但今天我尝试使用与对象初始化程序相同的代码,而不是仅仅分配给属性(在本例中为Name)。 我注意到有区别。 即使终结器永远不会被调用,即使我正在尽最大努力使垃圾收集器完成它的工作。

有人可以解释这个区别,还是我在C#编译器中发现了一个错误?

(我在Win7x64的VS2010 SP1中使用C#4)

谢谢。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace Zombie { class Program { static void Main(string[] args) { Console.WriteLine("Main thread: " + Thread.CurrentThread.ManagedThreadId); // case 1: this is where the problem is located. Zombie z = new Zombie { Name = "Guy" }; // object initializer syntax makes that the finalizer is not called. // case 2: this is not causing a problem. The finalizer gets called. //Zombie z = new Zombie(); //z.Name = "Guy"; WeakReference weakZombieGuyRef = new WeakReference(z, true); z = null; GC.GetTotalMemory(forceFullCollection: true); GC.Collect(); while (true) { Console.ReadKey(); if (weakZombieGuyRef.IsAlive) { Console.WriteLine("zombie guy still alive"); } else { Console.WriteLine("Zombie guy died.. silver bullet anyone?"); } Zombie.Instance = null; GC.AddMemoryPressure(12400000); GC.GetTotalMemory(forceFullCollection: true); GC.Collect(); } } } public class Zombie { public string Name { get; set; } public static Zombie Instance = null; ~Zombie() { Console.WriteLine(Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Finalizer called on zombie" + this.Name); lock (typeof(Zombie)) { Instance = this; GC.ReRegisterForFinalize(this); } } } } 

编辑:虽然下面的原始答案仍然准确,看起来它是调试信息和优化的混合,这在这里有所作为。

从我的实验:

 Compiler flags Result /o+ /debug- Finalizer runs /o+ /debug+ Finalizer runs /o- /debug- Finalizer runs /o- /debug+ Finalizer does *not* run 

当使用/o+在命令行上编译时,仍会在我的盒子上调用终结器。 我的猜测是你在调试器中运行 – 它改变了GC的行为。 如果没有调试器,GC将收集任何可以certificate永远不会被读取的内容。 使用调试器,我相信GC不会收集仍然在堆栈上有引用的任何对象,即使没有代码来读取有问题的变量。

现在使用对象初始化程序,编译器代码在堆栈上包含一个额外的引用。 这一行:

 Zombie z = new Zombie { Name = "Guy" }; 

有效地:

 Zombie tmp = new Zombe(); tmp.Name = "Guy"; Zombie z = tmp; 

只有在设置了所有属性才能执行对z的赋值。

我的猜测是这里的tmp变量是保持对象存活。

如果你想要不死的物体,你真的不需要弄乱终结者。 只需拥有所有实例的私有静态列表,并在创建它们时将对象添加到该列表:

 class Immortal { static List _immortals = new List(); public Immortal() { _immortals.Add(this); } }