关于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子句向上移动,因为我更喜欢使用该语法。 然后使用该块内部使用该资源调用其他块。