【问题标题】:What is the point of having using blocks in C# code? [duplicate]在 C# 代码中使用块有什么意义? [复制]
【发布时间】:2010-10-13 20:29:11
【问题描述】:

我看到大量具有以下语法的代码 sn-ps

using (RandomType variable = new RandomType(1,2,3))
{
   // A bunch of code here.

}

为什么不直接声明变量并使用它?

这种 Using 语法似乎只会使代码混乱并使其可读性降低。如果它是如此重要以至于该变量仅在该范围内可用,为什么不将该块放在一个函数中?

【问题讨论】:

标签: c# using-statement


【解决方案1】:

使用有一个非常明确的目的。

它是为与实现 IDisposable 的类型一起使用而设计的。

在您的情况下,如果 RandomType 实现 IDisposable,它将在块的末尾获得 .Dispose()。

【讨论】:

  • 如果它没有实现 IDisposable 我认为它实际上不会编译。
  • 确实会出现编译错误。
  • 您可以,但是在使用...时将任何内容转换为 IDisposable...(SomeType 作为 IDisposable)。如果 SomeType 没有实现 IDisposable,那么 null 被传入并且永远不会被释放,这是安全的。
  • 但是如果它作为null传入,那么using块中的代码很可能会因为NullReferenceException而崩溃,不是吗?
  • @Svish:不。它在编译器生成的 finally 块中进行空检查。这是使用的一大优势。
【解决方案2】:
using (RandomType variable = new RandomType(1,2,3))
{
   // A bunch of code here.
}

与以下内容几乎相同(有一些细微差别):

RandomType variable = new RandomType(1,2,3);

try
{
    // A bunch of code
}
finally
{
    if(variable != null)
        variable.Dispose()
}

请注意,在调用“Using”时,您可以将任何内容转换为 IDisposable:

using(RandomType as IDisposable)

finally 中的 null 检查将捕获任何实际上未实现 IDisposable 的内容。

【讨论】:

  • 不完全:'using' 还将名称“varialbe”限制在 using 块的范围内,因此您可以在同一范围内的另一个声明中重用该名称。但要点就在那里。
  • 根据 MSDN 添加了正确的“几乎相同”的答案。
  • @Joel 你是对的,但这是由 C# 编译器强制执行的。在 IL 中,RandomType 对象是在 try 块之外创建的。 @Brian 实际上,finally 块中的检查是 if (variable != null)。如果 RandomType 没有实现 IDisposable,C# 编译器将不允许您使用 using。
  • 在代码块周围添加 { } 也会限定该代码段的范围,如果您的对象不是一次性的,则无需使用。
  • @Sekhat:如果变量不是 IDisposable,我不建议您使用 using() 来确定变量的范围。我想你误解了我的意思。我只是在解释 using() 提供的功能的一部分。此外,您可能不知道它是否实现了 IDisposable 的代码。将它包装在 using() 中是一种安全的方法,可以在它实现 IDisposable 时将其处理掉,但您当时无法知道。这经常发生在泛型方法和扩展方法中。
【解决方案3】:

根据MSDN,如下using代码:

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

扩展为:

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}

而且它确实不会弄乱您的代码。实际上恰恰相反!

【讨论】:

    【解决方案4】:

    using 关键字提供了一种确定性的方式来清理对象分配的托管或非托管资源。如果您不使用 using 关键字,您有责任在完成该对象后调用 Dispose()(或在某些情况下,Close())。否则,资源可能直到下一次垃圾回收才会被清理,甚至根本不会被清理。

    【讨论】:

      【解决方案5】:

      不会,它不会弄乱您的代码,也不会降低可读性。

      using 语句只能用于 IDisposable 类型(即实现 IDisposable 的类型)。

      通过在 using-block 中使用该类型,当 using-block 的范围结束时,将使用该类型的 Dispose 方法。

      那么,告诉我哪些代码对你来说可读性较差:

      using( SomeType t = new SomeType() )
      {
         // do some stuff
      }
      

      SomeType t = new SomeType();
      
      try
      {
         // do some stuff
      }
      finally
      {
         if( t != null ) 
         {
            t.Dispose();
         }
      }
      

      【讨论】:

      • 实际上,这两种方法都增加了混乱——只是目前没有比“使用”更好的选择。太多 using 块(或 try..finally 块)会导致代码缩进地狱,并且还会限制对象的创建或处置位置(例如,您不能错开使用块)。
      【解决方案6】:

      在 using 语句中使用的对象必须实现 IDisposable,因此在范围结束时,您可以保证 Dispose() 将被调用,因此理论上,您的对象应该在该点被释放。在某些情况下,我发现它使我的代码更清晰。

      【讨论】:

        猜你喜欢
        • 2015-10-08
        • 2013-05-15
        • 1970-01-01
        • 2017-08-21
        • 2013-07-29
        • 2019-05-22
        • 2018-04-24
        • 2013-05-07
        • 1970-01-01
        相关资源
        最近更新 更多