2

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

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

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

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

检查 IL 是回答这些关于幕后发生的事情的好方法吗?

4

7 回答 7

6

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

从理论上讲,它应该。BCL 类都执行此操作,但要由库作者正确处理此问题。如果您使用的库正确完成,Dispose() 也应该 Close() [并且 Close() 将 Dispose() - 调用应该是可互换的]。

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

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

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

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

“检查 IL 是回答这些关于幕后发生的事情的好方法吗?”

这是一种方式——虽然是一种更困难的方式。在 MSDN 上阅读有关使用和流的信息,文档将用比尝试解析 IL 更简单的术语来解释它。但是,如果您好奇的话,IL 会确切地告诉您会发生什么。

于 2009-03-20T17:24:04.790 回答
3

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

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

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

是的,因为对象在退出 using 块时被处置。

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

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

于 2009-03-20T17:24:31.090 回答
1

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

CallingDispose应该采取任何必要的操作来处理资源,这应该与 calling 相似,如果不完全相同的话Close。然而,这是一个实现细节,不一定能保证(尽管我们可以预期 BCL 遵循此指南)。

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

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

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

处理包装另一个一次性对象Dispose的对象应该调用内部对象。调用CloseaFileStream会调用它的Dispose方法,所以它也会作用于两个流。

检查 IL 是回答这些关于幕后发生的事情的好方法吗?

检查 IL 肯定会明确回答这些问题中的大部分。正如@Rich所说,您也可以尝试调试自己的 Dispose 实现。当然,在您尝试自己弄清楚之前,还有 MSDN 文档可以开始,如果您不想在 IL 中乱七八糟,还可以使用 Reflector。

于 2009-03-20T17:23:32.277 回答
1

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

不必要。我有时会使用 Reflector 来检查 Close 和 Dispose 中实际发生的情况。

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

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

正如您所说,这方面有很多资源,但我将包含一些指南的 MSDN 链接:实现 Finalize 和 Dispose 以清理非托管资源

于 2009-03-20T17:24:44.833 回答
0

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

于 2009-03-20T17:22:10.767 回答
0

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

您应该在获得从数据库中获取的数据后立即处理它。不要让阅读器打开超过您需要的时间。如果您正在对数据进行任何实际工作,请使用 dataAdapter/dataset 而不是阅读器。

不知道。检查生成的 IL

于 2009-03-20T17:23:11.123 回答
0

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

于 2009-03-20T17:23:26.007 回答