【问题标题】:Is it better to use the [using] statement in C# or the [dispose] method? Does this apply to external (COM) objects?使用 C# 中的 [using] 语句或 [dispose] 方法更好吗?这是否适用于外部(COM)对象?
【发布时间】:2011-04-03 10:05:05
【问题描述】:

在处理完一个对象后,使用指令或处置指令哪个更好?

 using(FileStream fileStream = new FileStream(
            "logs/myapp.log",
            FileMode.Open,
            FileAccess.Read,
            FileShare.ReadWrite))
        {
            using(StreamReader streamReader = new StreamReader(fileStream))
            {
                this.textBoxLogs.Text = streamReader.ReadToEnd();
            }
        }

另一方面,当我处理 System.Net.Mail 时,我被告知我需要对对象进行 Dispose() 以释放任何杂散锁。

有没有一致的指导?如何判断在给定情况下对于给定对象什么更合适?

【问题讨论】:

  • CDO 已经过时了。微软可以让人们停止使用它的唯一方法是不撤回对它的任何支持。你自己一个人,即使在这里我估计。
  • @Hans Passant - 即使如此,.NET Framework 在下面使用 COM。 System.Web.Mail 实际上在 AFIK 内部使用了 CDO。也许在我每天使用的对象中潜伏着其他类似的 COM 对象。
  • 将一个过时的组件换成另一个是没有意义的。使用 System.Net.Mail
  • 我只是想强调需要处理一个可能是底层 COM 的 .NET 对象,而不是讨论可支持性主题。在仍受支持的情况下,最佳做法是什么?
  • 请注意,StreamReader 将在处置时处置其基本流。在您的示例代码中,如果您在 streamReaderusing 块之后,但在 fileStream using 块结束之前使用 fileStream,您将得到一个 ObjectDisposedException

标签: c# .net com dispose using-statement


【解决方案1】:

在退出时使用调用 Dispose。 using 更好,因为它可以确保调用 dispose。

【讨论】:

    【解决方案2】:

    using 块在到达块末尾时自动调用Dispose()

    【讨论】:

      【解决方案3】:

      using 语句(不是指令)在 finally 块中涉及对Dispose() 的隐式调用。所以这里没有矛盾。你能链接到那个讨论吗?

      官方定义
      using (x) { ... }

      try ... finally if (x != null) x.Dispose(); }

      什么更好?

      从符号的角度来看,using() { } 块。从技术上讲,它们是相同的。

      【讨论】:

      • @Jesse:是的,你是对的。我认为我的代码是一种简化。
      • 讨论是我在 Microsoft Premier 案例中收到的电子邮件线程的一部分,我无法转发它。该案例围绕通过 C# 使用 CDO 展开,尽管它通过 COM-Interop 工作,但不受 MSFT 支持
      • @Maker:那么我认为你的问题不是关于usingDispose(),而是关于如何/是否释放(清理)COM 对象。
      • @MakerOfThings - COM 对象不实现 IDisposable,因为 IDisposable 是一个 .NET 接口,而 COM 不是 .NET。如果你直接使用 COM 对象,你应该尝试Marshal.ReleaseComObject 来销毁它。
      • @MakerOfThings7:COM 对象通常包装在 C# 对象中。包装器将为您删除Dispose() 上的 COM 引用。
      【解决方案4】:

      这是一样的。用法很简单,如果您创建对象并仅在一种方法中使用它,则使用 using。如果你需要在方法调用之后让它保持活跃,那么你必须使用 Dispose()。

      COM 对象的运行时可调用包装器没有 Dispose() 方法。

      【讨论】:

      • COM 对象有什么特殊要求吗?
      • 这是一个加载的问题,有数以亿计的问题。如果您可以添加对它的引用,那么不,不太可能。终结器线程负责处理它们。
      • @MakerOfThings7:您必须明确释放您的 COM 对象可能已获取的所有资源。具体如何操作取决于您正在处理的 COM 对象。
      • COM 不是这样工作的,对象负责资源管理。必然如此,你不可能猜到它使用了什么。
      【解决方案5】:
      using(foo) 
      {
          foo.DoStuff();
      }
      

      只是语法糖:

      try
      {
          foo.DoStuff();
      }
      finally
      {
          if(foo != null)
              foo.Dispose();
      }
      

      所以我不确定争论的来源。 using 块调用 dispose。大多数人在可能的情况下更喜欢using 块,因为它们更清晰、更清楚地了解正在发生的事情。

      【讨论】:

      • 不完全是 - 您的 foo.Dispose() 实际上扩展为 ((IDisposable)foo).Dispose() 以处理显式实现 IDisposable Dispose() 方法的情况。
      • @Jesse,是的,好点。我忘记了显式实现。
      【解决方案6】:

      只要对象的生命周期在代码块内,就使用using,如果你的对象需要长生命周期,例如要在异步调用后被释放,你需要手动调用Dispose

      using 块比您记住对 Dispose 的调用要好得多,因为执行可以留下代码块的所有可能和不可能的方式。

      【讨论】:

        【解决方案7】:

        当您可以将对象包装在using 块。 using 块将对象的创建和处置放在 try/catch/finally 块中,以几乎保证对象将被正确处置。

        编译器比我靠谱。或者你。 =)

        MSDN 记录了using statement 并指出您可以在哪里获得C# language specification,您可以在其中查看第 8.13 节“使用语句”(至少在 v4.0 参考中是 8.13),它给出了对using 语句以及如何使用它。第五段给出以下内容:

        using 语句被翻译成 三个部分:获取、使用和 处理。资源的使用是 隐式包含在 try 语句中 其中包括一个 finally 子句。这 finally 子句处理 资源。如果空资源是 获得,则不调用 Dispose 已完成,不会抛出异常。

        【讨论】:

        • 这里是一个:在你自己类的Dispose()实现中处理私有成员对象
        • @recursive,说得好,不知道我是怎么忘记的。我必须假设我的大脑瞬间消失了! =) 不过现在已修复。
        • 这是另一个,处理私有成员(或this),因为您的代码可以安全地提前清理所有内容,从而提高效率,更重要的是安全(如果调用代码无法调用 dispose),即使该对象在外部看起来是“活动的”。仍然是内部的,但不适用于 using
        • dispose 的另外几个原因:工厂方法在创建 IDisposable 实例后抛出异常,或者构造函数在创建一个或多个 IDisposable 字段后抛出异常。如果工厂或构造函数自己不处理它们,它们将不会被处理(恕我直言,在抛出构造函数中缺少任何请求自动清理的方法是 C# 和 vb.net 的缺陷)。
        【解决方案8】:

        在任何地方都可以使用“using 语句”有一个非常重要的原因。

        如果通过 using 语句包装的代码抛出异常,您可以确定“使用对象”将被释放。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-05
          • 1970-01-01
          相关资源
          最近更新 更多