为什么我的重写Dispose方法没有被调用?

3

我目前正在使用.NET Compact Framework 3.5中的TextWriter类来将日志条目写入文件。这是一项非常常见且简单的任务,没有任何问题。但是,使用TextWriter并在所有数据被写入后调用Dispose会导致文件保持打开状态。

我的方法是初始化一个FileStream,然后使用创建的FileStream实例创建一个StreamWriter。然后,我使用静态方法Synchronized创建了一个同步的TextWriter。

为了调查为什么在数据被写入和刷新后文件不能被另一个进程访问,我从StreamWriter派生了一个类,并重写了Dispose方法,只是为了看看是否被调用。运行代码后发现重写的Dispose方法没有被调用,这让我感到困惑。

调用代码如下:

var fileStream = new FileStream("\\NAND_FLASH\\test.file", FileMode.OpenOrCreate);
var streamWriter = new ExtendedWriter(fileStream, Encoding.UTF8);

TextWriter textWriter = TextWriter.Synchronized(streamWriter);
textWriter.Dispose();

以下是派生类:

internal class ExtendedWriter : StreamWriter
{
    public ExtendedWriter(Stream stream) : base(stream)
    {
    }

    public ExtendedWriter(Stream stream, Encoding encoding) : base(stream, encoding)
    {
    }

    public ExtendedWriter(Stream stream, Encoding encoding, int bufferSize) : base(stream, encoding, bufferSize)
    {
    }

    public ExtendedWriter(string path) : base(path)
    {
    }

    public ExtendedWriter(string path, bool append) : base(path, append)
    {
    }

    public ExtendedWriter(string path, bool append, Encoding encoding) : base(path, append, encoding)
    {
    }

    public ExtendedWriter(string path, bool append, Encoding encoding, int bufferSize) : base(path, append, encoding, bufferSize)
    {
    }

    protected override void Dispose(bool disposing)
    {
        Trace.WriteLine("Extended writer dispose!");
        base.Dispose(disposing);
    }
}

有人能向我解释这种行为吗?

编辑: 更新问题文本,我忘了提到我正在使用.NET Compact Framework 3.5。


4
你提供的代码对我有效。你确定不仅仅是你的跟踪失败了吗? - Jon Skeet
确实,你是对的,在完整框架3.5下,代码将按预期运行。我昨天错过了测试。我的初始测试基于.NET Compact Framework 3.5(我忘记提到了)。在那里,ExtendedWriter的dispose方法没有被调用。 - xodder
嗯,那对我来说听起来相当不寻常 - 但不幸的是我无法轻易地为自己测试它 :( - Jon Skeet
也许我错过了什么,但在审查我的代码之后,我发现两个平台上的代码是相同的(在两个项目中使用相同的文件),我找不到任何解释它为什么会表现出那样行为的原因。 - xodder
你确定不需要处理你的FileStream吗?我知道一些包装的Stream接口会说他们关闭/处理底层流(例如XMLStreams,您可以指定行为),但我没有在这些方法中读到任何内容,表明它们将处理创建它的流。我建议在处理完TextWriter后,确保调用FileStream.Dispose()。 - Alan
当然,我可以自己关闭/处理其他底层流,但这不是问题所在。我想知道为什么我的重写处理程序从未被调用,它应该与完整的.NET框架相同。这是类/对象派生的基本机制。 - xodder
2个回答

2

我刚使用Reflector查看了CF 3.5 BCL中的TextWriter。

这是Dispose方法,你正在调用它:

public void Dispose()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

所以这里调用的是带参数的Dispose方法,它看起来像这样:
protected virtual void Dispose(bool disposing)
{
}

因此,这就解释了为什么你的衍生 StreamWriter 没有被处理 - TextWriter 不会在其包含的 StreamWriter 上调用 Dispose。你必须自己处理该对象。

确实有道理,遗憾的是这两个框架之间存在这样的差异。感谢您寻找解释。 - xodder
我认为这不是问题所在。TextWriter本身没有任何资源:在完整框架中,Dispose()的主体同样为空。TextWriter.Synchronized(TextWriter)创建了一个SyncTextWriter,它会处理其参数的释放。StreamWriter同样重写了Dispose以关闭其流。 - Tim Sparkles
不是的。我再次验证了一下。CF中的TextWriter.Synchronized确实创建了一个SyncTextWriter,但它没有Dispose实现,因此它继承自其基类TextWriter的实现,这些实现在答案中。这绝对是CF 3.5(可能还有2.0和3.9)的一个错误。 - ctacke

1

我认为并不是每个实现了IDisposable接口的东西都能做到它应该做到的。

例如,使用Microsoft Access数据库连接(OleDb)如果在using语句中打开连接,则永远不会关闭连接。

我猜你发现了另一个控件没有做到它应该做到的一切。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接