关于using语句的一些高级问题

时间:2009-03-20 17:18:19

标签: c# .net idisposable

我知道这里有很多关于如何使用using语句并调用Dispose()方法的线程。我已经阅读了大部分这些主题。

如果我调用Dispose(),它是否会调用Close()?

如果我想使用一个对象(比如SqlDataReader),但是在另一个代码块中再次使用它,我应该不调用Dispose()吗?这也意味着省略using语句。

另外,为了澄清,如果FileStream正在包装StreamWriter并且我在FileStream上调用dispose,这将调用Flush(),Close()和Dispose()(取决于Dispose()是否调用Close()) StreamWriter,对吧?同样,如果我在FileStream上调用Close,则只调用FileStream上的Flush()和Close()。

检查IL是否是回答这些问题的好方法?

8 个答案:

答案 0 :(得分:6)

“如果我调用Dispose(),它会调用Close()吗?”

从理论上讲,它应该。 BCL类都是这样做的,但由图书馆作者来正确处理这个问题。如果您正在使用的库已正确完成,Dispose()也应该是Close()[和Close()将Dispose() - 调用应该是可互换的。]

“如果我想使用一个对象(比如SqlDataReader),但是在另一个代码块中再次使用它,我应该不调用Dispose()吗?这也意味着省略using语句。”

正确。如果使用using语句,它将始终调用Dispose()。这将在您的其他块可以使用之前关闭数据阅读器。

“另外,为了澄清,如果FileStream正在包装StreamWriter并且我在FileStream上调用dispose,这将调用Flush(),Close()和Dispose()(取决于Dispose()是否调用Close())对于StreamWriter,对吗?同样,如果我在FileStream上调用Close,这将只调用FileStream上的Flush()和Close()。“

如果要围绕StreamWriter包装FileStream,我强烈建议您一致地处理它们。对两个成员使用单个using语句,因此它们都在块的末尾处理掉。这是最安全,最干净的方法。

“正在检查IL是一个很好的方式来回答这些关于幕后发生的事情的问题吗?”

这是一种方式 - 虽然是一种更难的方式。阅读有关使用和流的MSDN,文档将以比简单解释IL更简单的方式解释它。如果你好奇,IL会告诉你究竟发生了什么。

答案 1 :(得分:3)

  

如果我调用Dispose(),它是否会调用Close()?

如果正确实施,Close()和Dispose()也会这样做;这只是一个命名的事情。关闭文件比处理文件听起来更简单。请参阅Implementing Finalize and Dispose to Clean Up Unmanaged Resources esspecialy'自定义处理方法名称'。

  

如果我想使用一个对象(比如SqlDataReader),那么在另一个代码中再次使用它#   块,我不应该调用Dispose()吗?这也意味着省略using语句。

是的,因为对象在退出使用块时被处理掉。

  

另外,澄清一下,如果FileStream正在包装StreamWriter并且我在>上调用dispose。 FileStream,这将调用Flush(),Close()和Dispose()(取决于是否Dispos()   在StreamWriter上调用Close()),对吧?同样,如果我在FileStream上调用Close,>这只会调用FileStream上的Flush()和Close()。

这是另一种方式; StreamWriter基于底层流,关闭StreamWriter关闭可能是FileStream的底层流;请参阅MSDN以供参考。因此,StreamWriter的单个using语句就足够了。

答案 2 :(得分:1)

  

如果我调用Dispose(),它是否会调用Close()?

调用Dispose应该采取任何必要的措施来处置资源,该资源应该与调用Close类似,如果不相同的话。然而,这是一个实现细节,并不一定得到保证(尽管我们可以预期BCL遵循本指南)。

  

如果我想使用一个对象(比如SqlDataReader),但是在另一个代码块中再次使用它,我应该不调用Dispose()吗?这也意味着省略using语句。

如果您想再次使用该物体,绝对不应该丢弃它。但是,如果您要两次单独访问数据库,通常应该使用两个单独的连接。保持IDataReader的时间长于获取所需数据所需的时间通常不是一个好主意。

  

另外,为了澄清,如果FileStream正在包装StreamWriter并且我在FileStream上调用dispose,这将调用Flush(),Close()和Dispose()(取决于Dispose()是否调用Close()) StreamWriter,对吧?同样,如果我在FileStream上调用Close,则只调用FileStream上的Flush()和Close()。

处理包装另一个一次性对象的对象应该在内部对象上调用Dispose。在Close上拨打FileStream会在商品下调用其Dispose方法,因此它也会在两个流上运行。

  

检查IL是否是回答这些问题的好方法?

检查IL肯定会明确回答大部分问题。正如@Rich所说,您也可以尝试调试自己的Dispose实现。当然,在您尝试自己解决问题之前,还要开始使用MSDN文档,如果您不想在IL中使用,请使用Reflector。

答案 3 :(得分:1)

  
    

如果我调用Dispose(),它是否会调用Close()?

  

不一定。我有时会使用Reflector来检查Close和Dispose中实际发生了什么。

  
    

如果我想在另一个代码块中再次使用(...),我是否应该调用Dispose()?

  

正确。完成后调用Dispose。 并不意味着您总是希望长时间保持您的对象 - 您有时可以从创建多个实例(多个using构造)中受益 - 例如您可能希望尽快关闭连接,但在需要时再次创建新连接。

正如您所说,有很多资源,但我会在某些指南中加入MSDN链接:Implementing Finalize and Dispose to Clean Up Unmanaged Resources

答案 4 :(得分:1)

Dispose是链接到IDisposable接口和Disposable模式的主要方法。

Microsoft将类似Close()的方法称为特定于域的别名,并提供了这个想法。但它仍然取决于类的实现者,可能存在差异,例如能否重新打开。但总的来说,你不应该(不得不)关心。

sqlDataReader是一个很糟糕的例子,因为你不能重用它。这通常也是所有其他Disposable对象的最佳建议。

答案 5 :(得分:0)

调试此方法比通过IL代码更简单的方法是从您的IDisposable派生,覆盖除了调用base.[Method Name]()之外什么都不做的必要方法,并在每个方法中设置断点。然后,如果将派生类包装在using块中,您将看到这些调用的生命周期。

答案 6 :(得分:0)

不,IDisposable不需要Close(),但实现IDispose的对象可能足以将它包含在Dispose()方法中。

一旦掌握了数据库中的数据,就应该立即处理它。不要让读者打开超过您需要的时间。如果您正在使用真实处理数据,请使用dataAdapter / dataset而不是reader。

没有想法。检查Generated IL

答案 7 :(得分:0)

我尝试将using子句向上移动,因为我更喜欢使用该语法。然后使用该块中的那个资源调用其他块。