【问题标题】:When should I use "using" blocks in C#? [duplicate]我什么时候应该在 C# 中使用“使用”块? [复制]
【发布时间】:2010-10-08 16:53:32
【问题描述】:

是否存在我应该(或不应该?)使用“使用”块的特殊情况:

using(SomeType t = new SomeType()){
    ...
}

【问题讨论】:

  • 为什么这是一个社区维基?
  • @JaredPar,我也不明白。无论如何......他选择不派代表。 =[
  • 重复,可能被问过很多次。
  • @JaredPar;议论性和主观性。 using 声明的使用似乎因人而异。

标签: c# .net using


【解决方案1】:

当SomeType 类实现IDisposable 时。

【讨论】:

【解决方案2】:

只要类型实现IDisposable,就使用using,除非您无论如何要将它包装在try/catch 块中,那么您也可以(取决于您喜欢的外观)使用finally 块.

【讨论】:

  • 即使使用 finally ,我认为“使用”更可取。当您在“使用”中看到一个新的对象时,您就知道它的处置已得到处理。如果没有“使用”,您必须滚动并了解控制流程以说服自己没有泄漏。这需要不必要的努力。
【解决方案3】:

当 SomeType 实现 IDisposable 时。

这对开发人员来说是一个线索,即 SomeType 使用需要清理的非托管资源。

【讨论】:

    【解决方案4】:

    在这种情况下,using 语句对于实现 IDisposable 的类型很方便。当代码块退出using 语句的范围时,会隐式调用Dispose()。处理您想在使用后立即处理的物品时,这是一个好习惯。

    【讨论】:

      【解决方案5】:

      一种情况是当您想在代码块的开头做某事,然后在代码块的末尾无条件地撤消它(即使有抛出)。

      您构建(并在 using 中调用)的一次性类的 ctor 将执行该操作,然后 Dispose 方法将撤消该操作。这就是我通常使用它的方式。

      【讨论】:

      • 对于下一个需要处理该代码的开发人员来说,这听起来很混乱。为什么不使用(更标准的)“finally”块?
      • 它是 log4net 使用 (NDC.Push("string")) 所做的第一次调用推送并且 dispose 将项目从 NDC 堆栈中弹出
      【解决方案6】:

      主要规则是: * 当对象实现 IDisposable 接口时使用 USING 语句。

      此接口提供 Dispose 方法,该方法应释放对象的资源。如果不调用此方法,则对象将一直保留在内存中,因为 CLR 想要执行垃圾回收。如果程序员使用 USING 语句,那么最后对象将被释放,所有资源都将被释放。

      尽快释放所有不再使用的资源非常重要。

      有关它的更多信息,请访问此链接:microsoft

      【讨论】:

      • 可以措辞更清楚一点,但不值得投反对票
      【解决方案7】:

      其他人已经提到过“IDisposable”。

      但是使用“using”语句时的警告之一是, “using”中抛出的任何异常都不会被捕获 甚至认为无论如何都会处理“SomeType”。

      所以在下面的sn-p中,

      using (SomeType t = new SomeType()){
          throw new Exception("thrown within using");
      }
      

      throw new Exception("thrown within using"); 不应被忽视。

      【讨论】:

      • 一个异常被c#catch 关键字声明的catch 处理程序捕获。 “使用”对此没有任何影响。如果有适当的 'catch' 处理程序,将捕获在 'using' 中引发的异常。
      • 哦,我明白了。你是说“使用”将确保 Dispose 方法仍然会在“t”上被调用,即使在使用的主体中抛出异常。
      • 是的,斯科特。这正是我的观点。
      【解决方案8】:

      例子:

              using(SqlConnection MyConnection = new SqlConnection("Connection string"))
              {
                  MyConnection.Open();
      
                  //...
      
                  // 1. SQLConnection is a type that implements IDisposable
                  // 2. So you can use MyConnection in a using statement
                  // 3. When using block finishes, it calls Dispose method of 
                  // SqlConnection class
                  // 4. In this case, it will probably close the connection to 
                  // the database and dispose MyConnection object
      
              }
      

      您可以创建自己的实现 IDisposable 的对象:

      public class MyOwnObjectThatImplementsIDisposable : IDisposable
      {
      
          //... some code
      
          public void Dispose()
          {
              // Put here the code you want to be executed when the
              // using statement finish.
          }
      }
      

      所以你可以在 using 语句中使用 MyOwnObjectThanImplementsIDisposable 类型的对象:

              using(MyOwnObjectThatImplementsIDisposable MyObject = new MyOwnObjectThatImplementsIDisposable)
              {
      
                  // When the statement finishes, it calls the 
                  // code you´ve writed in Dispose method
                  // of MyOwnObjectThatImplementsIDisposable class
              }
      

      希望对你有帮助

      【讨论】:

        【解决方案9】:

        有些对象需要在你完成后采取一些行动。通常这是因为对象使用了某种需要处理的资源。例如,如果您有一个 File 类的文件对象,并且该对象从文件系统中打开一个文件,则需要再次关闭文件系统中的文件。

        如果您只是离开了文件对象,而忘记调用 file.Close(),则在垃圾收集器 (GC) 运行并发现没有任何东西仍在使用文件对象之前,它不会被清理。垃圾收集器何时运行应该留给公共语言运行时 (CLR) 来决定。如果在您处理完文件后 GC 有一段时间没有运行,则该文件可能会长时间保持打开状态。如果有很多文件对象,或者有东西想打开一个文件,但因为你留下的文件对象还在附近,这可能会造成很大的问题。

        为了解决这个问题,C# 提供了 IDisposable 接口。这有一种称为 Dispose 的方法。需要一些清理的类实现了这个 Dispose 方法。这为您提供了一种清理任何使用资源的对象的标准方法。有很多类需要调用 Dispose。这样做的问题是代码被对 Dispose 的调用所覆盖,并且它们很难遵循,因为您新建对象并调用 Dispose 以清理它的位置不同。因此,您必须仔细查看代码并非常小心地检查是否在正确的位置调用了 Dispose。

        为了解决这个问题,C# 引入了 'using' 关键字。您可以在新建对象的位置放置一个“使用”关键字,这样可以确保为您调用 Dispose。它保证无论发生什么都会调用 Dispose ......即使在 using 语句的主体内抛出异常。

        因此,当您想确保分配资源的对象将被清理时,您应该使用“使用”。


        using 只能用于在堆栈上声明的对象,即在函数中。它不适用于声明为类成员的对象。对于他们,您必须自己调用 Dispose。您可能必须在您的类中实现 Dispose,以便在它拥有的任何需要它的成员对象上调用 Dispose。


        需要调用的常用对象有:文件、数据库连接、Pen 和 Brush 等图形对象。


        有时当您希望两个操作一起发生时也使用它。例如,如果您想在输入代码块和退出代码块时编写日志语句,您可以编写一个可以像这样使用的日志类:

        using( Log log = new Log("Doing stuff") )
        {
            // Stuff
        }
        

        日志类的构造函数可以写出消息,Dispose方法也可以写出。实现终结器 (~Log) 以断言是否未调用 Dispose 方法以确保在“新日志”周围记住“使用”。

        【讨论】:

        • 很棒的总结! +1
        • 同意。这是一个很好的总结。
        【解决方案10】:

        当您应该有using 声明时,我看到很多其他答案。我想说明什么时候不应该有using声明:

        如果您需要在当前函数范围之外使用您的对象,请不要使用using 块。很好的例子是返回数据库连接的工厂方法或需要返回数据读取器的方法。在任何一种情况下,如果您使用 using 语句创建对象,它将在方法返回之前被释放,因此无法在方法之外使用。

        现在,您仍希望确定这些对象已被释放,因此您可能仍需要在某处使用using 语句。只是不要将它包含在实际创建对象的方法中。相反,您可以将函数调用本身包装在 using 语句中。

        【讨论】:

          【解决方案11】:

          也许值得一提的是,添加“using” lo C# 语言的根本原因如下:某些资源可能非常稀缺,以至于等待 GC 调用 IDisposable 是没有意义的。例如,数据库连接。如果你使用 try/catch/finally,你不会得到一个悬空连接,但是连接会一直挂起,直到 GC 没有启动,这可能需要一段时间(如果你没有明确地关闭它)。如果您使用“使用”(请原谅双关语),即使您忘记关闭它并且即使在 using 块内发生了一些异常,您也会立即释放连接。
          另一个原因,正如之前的帖子所提到的,程序员并不总是使用 finally 来清理。如果在异常情况下不使用 finally,你最终会导致资源泄漏......

          【讨论】:

            【解决方案12】:

            如果某些东西实现了IDispose,并且如果您想要处理的东西保留在数据库连接和文件句柄等非托管资源上,我还会添加使用using() 语句。

            如果它是一个带有List<T> 的普通对象,其中T 就像一个包含名称和地址的Customer 对象,那么你不需要。垃圾收集器足够聪明,可以为您管理这些。但垃圾收集器不会将连接返回到连接池或关闭文件句柄。

            【讨论】:

              【解决方案13】:

              您应该小心使用using 块的一个具体实例是使用 WCF 服务客户端。

              如this MSDN article 中所述,将 WCF 客户端(确实实现了 IDisposable)包装在 using 块中可以掩盖导致客户端处于故障状态的任何错误(如超时或通信问题) )。长话短说,当调用Dispose() 时,客户端的Close() 方法会触发,但由于它处于故障状态而抛出错误。然后,原始异常被第二个异常掩盖。不好。

              有多种解决方法,包括 MSDN 文章本身中的一种。其他可以在IServiceOriented 和blog.davidbarret.net 找到。

              我自己更喜欢最后一种方法。

              【讨论】:

              • 哇,这真是太可怕了。当我需要打开连接时,我一直在使用“使用”语句。
              【解决方案14】:

              如果你想要一个摘要规则。任何时候使用 IDisposable 的对象都不会被捕获,请使用 using。本质上,使用的是这种模式:

              try
              {
                //instantiate and use object
              }
              finally
              {
                //dispose object
              }
              

              如果你不需要catch,使用可以节省你的打字时间,这是一件好事。

              【讨论】:

                猜你喜欢
                • 2011-07-26
                • 2011-06-16
                • 1970-01-01
                • 2010-12-30
                • 2012-03-18
                • 2019-12-26
                • 2014-08-31
                • 2010-10-18
                相关资源
                最近更新 更多