【问题标题】:C# FileLogTraceListener throws exception when closingC# FileLogTraceListener 关闭时抛出异常
【发布时间】:2011-12-10 02:57:00
【问题描述】:

这是一个带有构造函数的日志类:

public QFXLogger(
        int maxFileSize,
        TraceLevel logLevel)
    {
        this.maxFileSize = maxFileSize;
        logSwitch.Level = logLevel;
        //Configure log listener
        traceListener = new FileLogTraceListener();
        traceListener.DiskSpaceExhaustedBehavior = DiskSpaceExhaustedOption.DiscardMessages;
        traceListener.CustomLocation = @".\Log";
        traceListener.BaseFileName = "QFXLog";
        traceListener.AutoFlush = true;
        //Remove all other listeners
        Trace.Listeners.Clear();
        //Add QFX listener
        Trace.Listeners.Add(traceListener);
        //Write header
        WriteSessionHeader();
    }

这是破坏者:

~QFXLogger()
    {
        WriteSessionFooter();
        traceListener.Close();
    }

我只想在记录器获得 GC 之前向底层流写入页脚。 没有析构函数一切都很好,但有了它我得到以下信息:

Unhandled Exception: System.ObjectDisposedException: Cannot access a closed file
.
at System.IO.__Error.FileNotOpen()
at System.IO.FileStream.Flush(Boolean flushToDisk)
at System.IO.FileStream.Flush()
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Flush()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.ReferencedStream.CloseS
tream()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.CloseCurrentStream()
at Microsoft.VisualBasic.Logging.FileLogTraceListener.Write(String message)
at System.Diagnostics.TraceInternal.Write(String message)
at System.Diagnostics.Trace.Write(String message)
at QFXShell.QFXLogger.WriteSessionFooter()
at QFXShell.QFXLogger.Finalize()

在我看来,底层流已经关闭了。

我怎样才能抑制这种关闭(基础流)或者这是另一个问题?

【问题讨论】:

  • @Ramhound WriteSessionFooter 除了这个之外什么都不做: Trace.Write(footerString);问题是我想在应用程序关闭之前写一个结束语句。
  • 这个 ObjectDisposedException 在我的类的 IDisposable 接口实现中调用 Stream.Dispose() 时发生在我身上,但在我删除对 Stream.Flush() 的调用函数调用后停止发生。
  • 糟糕,说得太早了。正如 Kelly Leahy 在他的网站上解释的那样,通过确保我的 Dispose(bool isFreeingManagedResources) 函数受到虚拟保护来解决了这个问题。以前,我将其设为私有。

标签: c# dispose destructor finalizer


【解决方案1】:

c# 中的终结器(析构函数)不应在此方法中使用。终结器用于释放非托管资源。当调用终结器时,access to other .net objects is not guaranteed 应该只释放您直接分配的非托管资源。

Finalize 操作有以下限制:

  • 不能保证两个对象的终结器以任何特定顺序运行,即使一个对象引用另一个对象也是如此。也就是说,如果对象 A 有对对象 B 的引用,并且两者都有终结器,那么当对象 A 的终结器启动时,对象 B 可能已经终结。

您需要做的是实现IDisposable Interface 以正确关闭您的日志文件。一些额外的信息可以在Kelly Leahy's IDisposable and Garbage Collection找到。

如果您没有一次性类可以提供帮助的情况(全局对象等),您始终可以自己实现Close 方法,以确保文件在发布之前有效。

【讨论】:

  • @谢谢,我会仔细看看。
【解决方案2】:

在析构函数中关闭跟踪器对象为时已晚。在这一刻,许多不再需要的对象已经可以被释放了。

我建议使用公共 Dispose 方法实现 IDisposable 接口,并在您知道不再需要此 QFXLogger 对象后立即调用此方法。在这个 Dispose 方法中,我会检查跟踪器对象是否不为 NULL,打开然后我会调用 Close。

详情请见Proper use of the IDisposable interface

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多