C#垃圾收集器似乎太早关闭了我的StreamWriter

For*_*bie 6 .net c# singleton garbage

我有一个单一的记录器类.在它的析构函数中,我调用Close()打印日志的页脚,然后关闭StreamWriter.

 public void Close()
    {
        WriteLogFileFooter();

        _logFile.Flush();

        _logFile.Close();
    }
Run Code Online (Sandbox Code Playgroud)

问题是当从程序中的其他地方调用System.Enviornment.Exit(1)时(我自己没有编写的部分),页脚永远不会打印,我的记录器会因尝试写入封闭流而抛出异常.我只能假设Exit命令导致我的StreamWriter在我的Singleton被破坏之前被关闭.我尝试在我的StreamWriter上使用GC.SupressFinalize(),但这似乎没有帮助.

Eri*_* J. 12

您违反了终结器的一条明确规则:

Finalize方法不应引用任何其他对象.

http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=VS.90).aspx

在应用程序退出时收集对象之前,收集引用的托管对象完全有可能被收集.

UPDATE

如果您需要在应用程序退出时清理托管资源,则可以挂接AppDomain 的ProcessExit事件,而不是依赖于终结器执行的非确定性行为.

.NET控制台应用程序退出事件

  • 它完全在上下文中.它应该释放资源(*表示非托管*资源)*和*不保存对[*managed*]对象的引用.我所引用的部分没有任何内容使得答案不准确. (2认同)

Ken*_*rey 3

您应该让您的记录器实现IDisposable,并在using块中使用它。这意味着它将被确定性地处置,而现在它正在被非确定性地破坏。

错误的原因是您的流有时会在记录器之前关闭,因为Exit基本上会破坏所有内容(不确定)并退出。您应该使用确定性模式 ( IDisposable) 来避免这种情况。

实际上,析构函数在 C# 中很少有用,因为它们是不确定的。它们只值得用于释放非托管资源。

另外,实现IDisposable可能会使使用单例变得不方便。我个人认为最好创建一个在整个程序中使用并在最后处理的实例,而不是显式的单例。

  • 这也没有回答OP的问题。 (2认同)