class Program : CriticalFinalizerObject
{
static void Main(string[] args)
{
Program p = new Program();
TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace.txt");
Trace.Listeners.Clear(); // Remove default trace listener
Trace.Listeners.Add(listener);
Trace.WriteLine("First Trace"); // Generate some trace messages
Trace.WriteLine("Perhaps last Trace.");
}
~Program()
{
Trace.Close();
}
}
我得到文件大小= 0
finilizer 应执行,因为我来自CriticalFinalizerObject
我不想在Finalizer中使用Trace.Close()。
在@eric Lippert回复之后:我重新编辑了代码,试图将其与:约束执行区域(但仍然没有成功)
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
class Program : CriticalFinalizerObject
{
static void Main(string[] args)
{
RuntimeHelpers.PrepareConstrainedRegions();
try
{
}
catch (Exception e)
{
}
finally
{
Program p = new Program();
TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace1.txt");
Trace.Listeners.Clear();
Trace.Listeners.Add(listener);
Trace.WriteLine("First Trace");
Trace.WriteLine("Perhaps last Trace.");
}
}
~Program()
{
Trace.Flush();
}
}
答案 0 :(得分:11)
正如文件明确指出:
在从CriticalFinalizerObject类派生的类中,公共语言运行库(CLR)保证所有关键的终结代码都有机会执行,前提是终结器遵循CER的规则,即使在CLR强行卸载的情况下也是如此应用程序域或中止线程。如果终结器违反了CER的规则,则可能无法成功执行
你的终结器是否遵循约束执行区的所有规则?
更新:
您已经更新了代码,试图使其遵循约束执行区域的规则,但我没有看到您已正确完成的任何证据。规则很清楚;约束执行区域中的终结器绝对不能执行以下任何操作:
你的终结者会做这五件事吗?如果确实如此,则不要求CLR满足您对终结器始终运行的期望。
此外:暂时忘记约束执行区域,因为您现在的程序甚至不是线程安全。你已经在程序中写了一个令人讨厌的竞争条件。
在跟踪开始之前,什么会阻止垃圾收集p ?没有!抖动知道p将永远不会再次使用,完全在其分配后立即收集它的权利。刷新可以在终结器线程上随时发生,包括在跟踪写入发生之前,或者在其中任何一个中间。
答案 1 :(得分:10)
因为您没有创建Program类的实例。
您可以阅读更多here:
在对象变得不可访问之后,将自动调用此方法,除非通过调用SuppressFinalize来豁免对象的最终化。在关闭应用程序域期间,会自动调用Finalize,这些对象不会被终止,即使是那些仍然可访问的对象。 Finalize在给定实例上仅自动调用一次,除非使用ReRegisterForFinalize和GC等机制重新注册该对象。随后未调用GC.uppressFinalize。
所以,如果你想要调用finilizer,你需要有对象的实例。
更新:如果要写入消息,请考虑使用Trace.AutoFlush = true;
。
更新:(为什么不调用关闭功能?)
实际上你调用了Close函数(如果在其他终结器中没有例外)。如果你保持默认的TraceListener(删除Trace.Listeners.Clear()
调用),你会看到所有字符串都成功写入Output窗口。
问题在于StreamWriter(在TextWriterTraceListener中创建)没有终结器。因此它不会将所有数据刷新到文件。你需要做什么:
FileStream file = new FileStream(@"C:\trace.txt", FileMode.OpenOrCreate);
StreamWriter writer = new StreamWriter(file);
GC.SuppressFinalize(file);
GC.SuppressFinalize(file.SafeFileHandle);
var listener = new TextWriterTraceListener(writer);
实际上,您需要在终结器上手动关闭文件。
答案 2 :(得分:0)
在C#中你无法确定何时或者你的终结器被调用,因为GC会处理它。因此,如果你有一些资源需要发布,最好创建一个实现IDisposable
的类并像这样使用它:
using (MyResourceHolder rh = new MyResourceHolder()) {
// ...
} // rh.Dispose() is called implicitly
在Dispose方法中,您可以拨打Trace.Close()
。
有关IDisposable
的良好实施,请参见http://msdn.microsoft.com/en-us/library/system.idisposable.aspx。