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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

“检查IL是一个很好的方式来回答这些关于引擎盖下发生的事情的问题吗?”

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

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

如果正确实现,Close()和Dispose()也会这样做; 这只是一个命名的事情。 关闭文件比处理文件听起来更简单。 请参阅实现Finalize和Dispose以清理非托管资源,特别是“自定义Dispose方法名称”。

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

是的,因为对象在退出使用块时被丢弃。

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

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

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

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

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

正确。 完成后调用Dispose。 但这并不意味着你总是想让你的对象保持很长时间 – 你有时可以从创建多个实例(多个using构造)中受益 – 例如你可能想尽快关闭一个连接,但是然后创建你需要的时候再来一个新的。

正如你所说,有很多资源,但我会包含一些指导的MSDN链接: 实现Finalize和Dispose来清理非托管资源 。

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

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

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

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

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

一旦掌握了从数据库获得的数据,就应该立即处理它。 不要让读者打开超过您需要的时间。 如果您正在使用数据进行任何实际操作 ,请使用dataAdapter / dataset而不是reader。

不知道。 检查Generated IL

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