【问题标题】:Some advanced questions on the using statement关于using语句的一些高级问题
【发布时间】:2009-03-20 17:18:19
【问题描述】:

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

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

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

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

检查 IL 是否是回答这些关于幕后发生的问题的好方法?

【问题讨论】:

  • 当您说“FileStream 正在包装 StreamWriter”时,我相信您实际上是指“Stream 类的实现中的 FileStream”?或者你是用你的自定义类包装 StreamWriter 吗?
  • 我的意思是类似 FileStream fs = sw.Write(其中 sw 是 StreamWriter),但 Write() 返回 void。

标签: c# .net idisposable


【解决方案1】:

“如果我调用 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()。"

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

“检查 IL 是回答这些问题的好方法吗?”

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

【讨论】:

    【解决方案2】:

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

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

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

    是的,因为对象在退出 using 块时被释放。

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

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

    【讨论】:

    • 不,它们不是一回事。
    • 理论上,任何在库中具有 Close() 方法的对象都应该实现 Close() 和 Dispose() 以便可互换。有关原因的详细信息,请参阅 .NET 设计指南一书。话虽如此,这并不是一个硬性要求 - 一个库可以以非常不同的方式编写。
    • 那当然是对的;你可以,但你喜欢什么,但你真的不应该这样做或记录得那么好。你甚至可以在 Dispose() 中做任何你想做的事情;由于您的代码的操作没有得到/无法检查,您必须相信该方法确实符合您的期望。
    【解决方案3】:

    如果我调用 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。在 FileStream 上调用 Close 将在 good 下调用其 Dispose 方法,因此它也会作用于两个流。

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

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

    【讨论】:

      【解决方案4】:

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

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

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

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

      正如你所说,这方面有很多资源,但我会附上 MSDN 链接以获取一些指导:Implementing Finalize and Dispose to Clean Up Unmanaged Resources

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

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

          不知道。检查生成的 IL

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-04-30
              • 2010-12-09
              • 1970-01-01
              • 2012-05-14
              • 1970-01-01
              相关资源
              最近更新 更多