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

本文关键字:还是 Dispose Close 对象 调用 我应该 | 更新日期: 2023-09-27 18:09:22

StreamStreamReaderStreamWriter等类实现了IDisposable接口。这意味着,我们可以在这些类的对象上调用Dispose()方法。他们还定义了一个叫做Close()public方法。这让我很困惑,当我用完对象后,我应该叫什么?如果我两个都打电话呢?

我的当前代码是:

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()方法。但我也调用Close()方法。对吗?

请告诉我使用流对象的最佳实践。: -)

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

  • 如何使用FTP下载文件

好吗?

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

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

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

StreamReader是:

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

StreamReader中的Dispose(bool disposing)重写为:

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();
}

它不影响代码的行为,但它有助于可读性。

不,您不应该手动调用这些方法。在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()

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

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

StreamWriter。关闭:Close的实现调用Dispose方法,传递一个真值。

流。Close:该方法调用Dispose,指定true释放所有资源。

所以,这两个是同样有效的:

/* Option 1, implicitly calling Dispose */
using (StreamWriter writer = new StreamWriter(filename)) { 
   // do something
} 
/* Option 2, explicitly calling Close */
StreamWriter writer = new StreamWriter(filename)
try {
    // do something
}
finally {
    writer.Close();
}

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

无论如何,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,由于兼容性原因,它不能被删除。

这是一个老问题,但是你现在可以( c# 8.0)编写using语句而不需要阻塞每个语句。当包含块完成时,它们将以相反的顺序被处理。

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://learn.microsoft.com/en - us/dotnet/csharp/language reference/proposals/csharp - 8.0 -/-使用

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

IDisposable.Dispose的契约明确要求在一个永远不会再使用的对象上调用它是无害的,所以我建议在每个IDisposable对象上调用IDisposable.Dispose或一个名为Dispose()的方法,无论是否也调用Close()

只是为了补充其他答案,从c# 8.0开始,您不需要打开代码块来使用using语句

if (...) 
{ 
   using FileStream f = new FileStream(@"C:'users'jaredpar'using.md");
   // statements
}
// Equivalent to 
if (...) 
{ 
   using (FileStream f = new FileStream(@"C:'users'jaredpar'using.md")) 
   {
    // statements
   }
}

文档:

https://learn.microsoft.com/en - us/dotnet/csharp/language reference/proposals/csharp - 8.0 -/-使用