C# 为什么我的关闭函数不是';你没打电话吗?

C# 为什么我的关闭函数不是';你没打电话吗?,c#,.net,garbage-collection,clr,finalizer,C#,.net,Garbage Collection,Clr,Finalizer,我得到的文件大小为0 finilizer应该执行,因为我从CriticalFinalizerObject 我不想在终结器中使用Trace.Close() 编辑 @eric Lippert回复后:我重新编辑了代码,试图将其匹配到:受约束的执行区域(但仍然否成功) 因为您没有创建程序类的实例 你可以阅读更多: 此方法在对象变得不可访问后自动调用,除非通过调用SuppressFinalize免除了对象的终结。在关闭应用程序域的过程中,对不能免于终结的对象(即使是仍然可以访问的对象)自动调用Finali

我得到的文件大小为0

finilizer应该执行,因为我从
CriticalFinalizerObject

我不想在终结器中使用Trace.Close()

编辑 @eric Lippert回复后:我重新编辑了代码,试图将其匹配到:受约束的执行区域(但仍然成功)


因为您没有创建程序类的实例

你可以阅读更多:

此方法在对象变得不可访问后自动调用,除非通过调用SuppressFinalize免除了对象的终结。在关闭应用程序域的过程中,对不能免于终结的对象(即使是仍然可以访问的对象)自动调用Finalize。除非使用诸如ReRegisterForFinalize和GC.SuppressFinalize等机制重新注册对象,否则在给定实例上仅自动调用Finalize一次

所以,若要调用finilizer,就需要有object的实例

更新:考虑使用<代码> Trace.AutoFlush = TRUE;<代码>如果您希望写入消息

更新:(为什么不调用Close函数?) 实际上,关闭函数是被调用的(若在其他终结器中并没有异常发生)。如果您将保留默认的TraceListener(删除
Trace.Listeners.Clear()
call),您将看到所有字符串都成功写入了输出窗口

这里的问题是StreamWriter(在TextWriterTraceListener内创建)没有终结器。所以它不会将所有数据刷新到文件中。您需要做的是:

  [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();
        }
    }
实际上,您需要在终结器上手动关闭文件。

在C#中,您无法确定何时或是否调用了终结器,因为GC会处理这个问题。因此,如果您有一些资源要发布,最好创建一个实现
IDisposable
的类,并像这样使用它:

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);
在Dispose方法中,可以调用
Trace.Close()


有关
IDisposable

的良好实现,请参阅,因为文档中明确说明:

在从CriticalFinalizerObject类派生的类中,公共语言运行库(CLR)保证所有关键终结代码都有机会执行,只要终结器遵循CER的规则,即使在CLR强制卸载应用程序域或中止线程的情况下也是如此。如果终结器违反CER的规则,它可能无法成功执行

终结器是否遵循受约束执行区域的所有规则

更新:

您已经更新了代码,试图使其遵循受约束执行区域的规则,但我看不到任何证据表明您这样做是正确的。规则很明确,;受约束执行区域中的终结器绝对不能执行以下任何操作:

  • 分配内存
  • 框a值类型
  • 获得锁
  • 调用任意虚拟方法
  • 调用任何缺少可靠性契约的方法
您的终结器是否执行这五项操作中的任何一项?如果是这样,则不要求CLR满足您始终运行终结器的愿望

此外:暂时不要考虑受约束的执行区域,因为现在的程序甚至不是线程安全的。你在程序中写了一个恶劣的比赛条件


在跟踪开始之前,是什么阻止了垃圾收集p的抖动?没有什么!jitter知道p永远不会被再次使用,并且完全有权在分配后立即收集它。刷新可能在终结器线程上的任何时间发生,包括在跟踪写入发生之前,或者在其中任何一个中间发生。p> +1。我觉得自己真的很傻,因为我没有马上看到这一点。很好。@RoyiNamir:你能更新你的代码来显示
程序
类的实例化,这样其他人就不会得出同样的结论吗?整个问题是我学习GC内部的过程…:),所以我不想使用
Trace.AutoFlush
,而是想知道为什么不调用它。@Tigran仍然大小0.... 试试看……我只是假设终结器甚至没有被调用,因为程序将被关闭。@Tigran这就是CriticalFinalizerObject存在的原因。。。。为了确保它被称为……再次,我认为这是一个特殊的情况,或者更好的情况是一个具有特殊行为的情况。因为你要在实际上是你应用程序主要入口的课堂上表演。@Tigran所以不要在面试问题中问它…:)它有不可预测的结果……贾斯德,你读过这些帖子了吗?:)整个问题是为什么它没有被调用。我知道处置模式和其他解决方案。谢谢。是的,我读过了,我告诉过你,你不能确定是否调用了终结器,也许有时是,有时不是。所以你根本不应该用它来做这样的用途。你应该告诉我们答案,埃里克,如果你想让这成为一个答案的话…;-)提示:它不是。考虑阅读CER规则:。然后考虑评估规则(有一个方便的子弹列表)。特别是什么是Trace.Flush上的可靠性合同?也许您使用终结器/CER做了错误的事情。ProTip:编写可靠的(与CER相关的)代码是一项挑战。如果您不完全了解解决方案领域中的工具,您可能会把它搞砸。
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);
using (MyResourceHolder rh = new MyResourceHolder()) {
    // ...
} // rh.Dispose() is called implicitly