我应该为流对象调用Close()或Dispose()吗?

时间:2011-09-23 06:05:26

标签: c# stream idisposable streamreader streamwriter

StreamStreamReaderStreamWriter等类会实现IDisposable接口。这意味着,我们可以在这些类的对象上调用Dispose()方法。他们还定义了一个名为public的{​​{1}}方法。现在这让我感到困惑,一旦我完成对象,我应该怎么称呼?如果我同时打电话怎么办?

我目前的代码是:

Close()

如您所见,我编写了using (Stream responseStream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(responseStream)) { using (StreamWriter writer = new StreamWriter(filename)) { int chunkSize = 1024; while (!reader.EndOfStream) { char[] buffer = new char[chunkSize]; int count = reader.Read(buffer, 0, chunkSize); if (count != 0) { writer.Write(buffer, 0, count); } } writer.Close(); } reader.Close(); } } 个构造,它们会自动在每个对象上调用using()方法。但我也称Dispose()方法。是不是?

请在使用流对象时建议最佳做法。 : - )

MSDN示例不使用Close()构造,并调用using()方法:

好吗?

6 个答案:

答案 0 :(得分:95)

快速跳转到Reflector.NET显示Close()上的StreamWriter方法是:

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

StreamReader是:

public override void Close()
{
    this.Dispose(true);
}

Dispose(bool disposing)中的StreamReader覆盖是:

protected override void Dispose(bool disposing)
{
    try
    {
        if ((this.Closable && disposing) && (this.stream != null))
        {
            this.stream.Close();
        }
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {
            this.stream = null;
            /* deleted for brevity */
            base.Dispose(disposing);
        }
    }
}

StreamWriter方法类似。

所以,阅读代码很明显,你可以致电Close()& Dispose()可以随时随地以任意顺序访问流。它不会以任何方式改变行为。

因此,归结为使用Dispose()Close()和/或using ( ... ) { ... }是否更具可读性。

我个人的偏好是using ( ... ) { ... }应该尽可能使用,因为它可以帮助你“不用剪刀”。

但是,虽然这有助于提高正确性,但确实会降低可读性。在C#中,我们已经有了大量的花括号,所以我们怎么知道哪一个实际上在流上执行了关闭呢?

所以我认为最好这样做:

using (var stream = ...)
{
    /* code */

    stream.Close();
}

它不会影响代码的行为,但它确实有助于提高可读性。

答案 1 :(得分:45)

不,你不应该手动调用这些方法。在using块的末尾,自动调用Dispose方法,该方法将释放非托管资源(至少对于标准的.NET BCL类,如流,读取器/写入器等)。所以你也可以写这样的代码:

using (Stream responseStream = response.GetResponseStream())
    using (StreamReader reader = new StreamReader(responseStream))
        using (StreamWriter writer = new StreamWriter(filename))
        {
            int chunkSize = 1024;
            while (!reader.EndOfStream)
            {
                 char[] buffer = new char[chunkSize];
                 int count = reader.Read(buffer, 0, chunkSize);
                 if (count != 0)
                 {
                     writer.Write(buffer, 0, count);
                 }
            }
         }

Close方法调用Dispose。

答案 2 :(得分:12)

文档说这两种方法是等价的:

  

StreamReader.Close:Close的这个实现调用Dispose方法传递一个真值。

     

StreamWriter.Close:   Close的这个实现调用Dispose方法传递一个真值。

     

Stream.Close:此方法调用Dispose,指定true以释放所有资源。

因此,这两者同样有效:

/* Option 1 */
using (StreamWriter writer = new StreamWriter(filename)) { 
   // do something
} 

/* Option 2 */
StreamWriter writer = new StreamWriter(filename)
try {
    // do something
}
finally {
    writer.Close();
}

就个人而言,我会坚持使用第一个选项,因为它包含较少的“噪音”。

答案 3 :(得分:4)

在许多支持Close和Dispose方法的类中,两个调用是等效的。但是,在某些类中,可以重新打开已关闭的对象。一些这样的类可以在关闭后保留一些资源,以便允许重新开放;其他人可能不会在关闭时保留任何资源,但可能会在Dispose上设置一个标志,以明确禁止重新打开。

IDisposable.Dispose的合同明确要求在一个永远不会再次使用的对象上调用它将是最无害的,因此我建议在每个IDisposable对象上调用IDisposable.Dispose或一个名为Dispose的方法,无论是没有人也叫Close。

答案 4 :(得分:0)

这是一个古老的问题,但是您现在可以使用语句编写而不需要阻塞每个语句。当包含块完成时,将以相反的顺序处理它们。

using var responseStream = response.GetResponseStream();
using var reader = new StreamReader(responseStream);
using var writer = new StreamWriter(filename);

int chunkSize = 1024;
while (!reader.EndOfStream)
{
    char[] buffer = new char[chunkSize];
    int count = reader.Read(buffer, 0, chunkSize);
    if (count != 0)
    {
        writer.Write(buffer, 0, count);
    }
}

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/using

答案 5 :(得分:0)

关于其价值,the source code for Stream.Close解释了为什么有两种方法:

// Stream used to require that all cleanup logic went into Close(),
// which was thought up before we invented IDisposable.  However, we
// need to follow the IDisposable pattern so that users can write
// sensible subclasses without needing to inspect all their base
// classes, and without worrying about version brittleness, from a
// base class switching to the Dispose pattern.  We're moving
// Stream to the Dispose(bool) pattern - that's where all subclasses
// should put their cleanup now.

简而言之,Close之所以存在,是因为它早于Dispose,并且出于兼容性原因不能删除。