c# - 抑制 .NET 中流的过早终结

标签 c# .net garbage-collection

我有以下类似记录器的类模式:

public class DisposableClassWithStream : IDisposable
{
    public DisposableClassWithStream()
    {
        stream = new FileStream("/tmp/file", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
        writer = new StreamWriter(stream);
    }

    public void WriteLine(string s)
    {
        writer.WriteLine(s);
    }

    ~DisposableClassWithStream()
    {
        Dispose();
    }

    private readonly object disposableLock = new object();
    private bool isDisposed;

    public void Dispose()
    {
        lock (disposableLock)
        {
            if (!isDisposed)
            {
                writer.Close();
                stream.Close();
                GC.SuppressFinalize(this);
                isDisposed = true;
            }
        }
    }

    private FileStream stream;
    private TextWriter writer;
}

以及使用此类的非常简单的代码:

public static void Main(string[] args)
{
    var t = new DisposableClassWithStream();
    t.WriteLine("Test");
}

代码在 .net 和 mono 上抛出(非确定性)ObjectDisposedException 是由对象 writer 的方法 Close 引起的,因为它试图将缓冲区刷新到已处理的 stream

我理解的原因是GCwriter之前完成了stream。如何更改类模式以确保 stream 不会在 writer 之前被释放?

我厌倦了在构造函数中使用 GC.SuppressFinalize(writer),但我不确定它是不是太 hacky 了。

编辑:


我想首先解决终结器的问题。如问题开头所述,该类用作记录器,我想确保在关闭进程之前将来自 writer 的所有行都刷新到硬盘。

最佳答案

不要创建终结器,除非您的IDisposable 实现确实适用于非托管资源。 FileStreamStreamWriter 是托管资源。

此外,由于SafeHandle引入后,很难想象用例,当任何非托管资源无法包装到托管 SafeHandle 中时。不要盲目地遵循 MSDN 中的 IDisposable 实现 - 这没关系,但它适用于您的类型同时操作托管和非托管资源的情况。

完全删除终结器,并从 Dispose 中丢弃 GC.SuppressFinalize(this);:

public void Dispose()
{
    lock (disposableLock)
    {
        if (!isDisposed)
        {
            writer.Close();
            stream.Close();
            isDisposed = true;
        }
    }
}

更新

终结器用于非托管资源清理。
您可以将终结器视为关闭文件句柄、网络套接字等的地方。这不是任何应用程序逻辑的地方。通常,托管对象在终结期间处于不可用状态 - 无法保证其任何 IDisposable(如 streamwriter 在您的示例)尚未最终确定。

如果您想确定该特定日志消息是否已刷新到文件中,则写入它并调用 writer.Flush()。否则,如果您不希望立即刷新,请确保您在应用程序关闭时为记录器调用 dispose。另请注意,您无法防止进程终止,因此不要对记录器过于偏执。

关于c# - 抑制 .NET 中流的过早终结,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24279621/

相关文章:

c# - 通过Timer控制函数调用c#

c# - 在 C# 中从 XML 解析为 JSON 时如何避免 ROOT 元素

.net - "Memory Pressure"是什么意思?

Java 和调用垃圾收集器

c# - 使用 WatiN 使 IE session 过期

c# - 在 ASP.NET 4.5 webforms 应用程序中设置 OAuth redirect_uri 的位置

c# - 如何在 C# 中的 Xaml 中显示 HTML

javascript - knockout 组列表为带有对象的更小列表

.net - 单元测试 Entity Framework

java - oracle java官方文档中处理器吞吐量的数字是多少