简体   繁体   English

C#:IDisposable类需要'using'子句吗?

[英]C#: IDisposable classes need 'using' clause?

If am using an IDisposable class, should I always use a using clause, for example: 如果正在使用IDisposable类,则应始终使用using子句,例如:

using (MyClass myclass = new MyClass())
{
...
}

The using statement ensures that Dispose is called to free the resources even if an exception occurs or if the object goes out of scope. using语句确保即使发生异常或对象超出范围,也将调用Dispose以释放资源。

This is simpler than using the following code block, 这比使用以下代码块更简单,

try
{
   ...
}
catch()
{
   // Handle exception
}
finally
{
    // Free resources by calling Dispose()
}

Note 注意
The catch block is not necessary if one does not want to handle the exception . 如果不想处理exception则不必使用catch块。 In that case, a try ... finally block would suffice (as pointed in other answers). 在这种情况下, try ... finally块就足够了(如其他答案所示)。


Alternative way 替代方式
You can create multiple, instance of the disposable object in the same using statement, for example 您可以在同一using语句中创建多个一次性对象的实例,例如

using(MyClass myclass1 = new MyClass(), 
      MyClass myclass2 = new MyClass())
{
    ...
}


Example
From Understanding the 'using' statement in C# 通过了解C#中的'using'语句

using (MyResource myRes = new MyResource())
{
    myRes.DoSomething();
}

gets translated to (by the CLR ) 被( CLR )翻译为

MyResource myRes= new MyResource();
try
{
    myRes.DoSomething();
}
finally
{
    // Check for a null resource.
    if (myRes!= null)
    {
        // Call the object's Dispose method.
        ((IDisposable)myRes).Dispose();
    }
}

You can have a look at the generated MSIL in the link specified at the beginning of the example. 您可以在示例开头指定的链接中查看生成的MSIL


More information 更多信息

It makes it much more readable code. 它使代码更具可读性。 So, as a rule you should declare and instantiate the object in a using block. 因此,通常应在using块中声明并实例化该对象。 It ensures that the Dispose method is called even if an exception happens. 它确保即使发生异常也将调用Dispose方法。 At compile time the same expression would look something like this : 在编译时,相同的表达式如下所示

{
  MyClass myclass = new MyClass ();
  try {
    //Do something with myclass
  }
  finally {
    if (myclass != null)
      ((IDisposable)myclass).Dispose();
  }
}

the using clause is syntax sugar on the following code block: using子句是以下代码块上的语法糖:

MyClass myclass = null;
try
{
     myclass = new MyClass();
     //do work
}
finally
{
     if(myclass != null)
          myclass.Dispose();
}

If a class implements IDisposable you should ensure that Dispose is called when you are done using it. 如果一个类实现IDisposable,则应确保在使用完Dispose后调用它。 The using clause is just an easy way to do it. using子句只是一种简单的方法。 So you don't have have to use "using" to do it, but you should ensure that it is called. 因此,您不必使用“ using”来执行此操作,但应确保调用了它。

If a class implements IDisposable you should always call Dispose when you are done with the object. 如果类实现IDisposable ,则在处理完对象后应始终调用Dispose C# provides the using statement as syntactic sugar to make this easier. C#提供using语句作为语法糖,以使其变得更容易。 So, it's not required to use using to call Dispose . 因此,不需要使用using来调用Dispose That said, it is the de facto standard way to invoke Dispose . 就是说,这是调用Dispose事实上的标准方法。 ie if your code is not using using and is instead invoking Dispose in finally blocks it will look a bit odd to experienced coders. 即,如果您的代码未使用using而是在finally块中调用Dispose ,那么对于有经验的编码人员而言,这看起来有些奇怪。

The expansion of your using block (assuming MyClass is a reference type) is: using块的扩展(假设MyClass是引用类型)为:

{
    MyClass myclass = new MyClass();
    try {
        //...
    }
    finally {
        if (myclass != null) ((IDisposable)myclass).Dispose();
    }
}

The using version is easier to code and easier to read. using版本更易于编码和阅读。

Simply put, if it implements IDisposable, and you want to have that method called (also on exceptions in the finally block when you are doing. Use using. 简而言之,如果它实现了IDisposable,并且您想调用该方法(在执行操作时,也会在finally块中的异常上进行调用。请使用using。

The GC will NOT call Dispose() for you! GC不会为您调用Dispose()! Some classes implement a finalizer ~ClassName() but try to avoid this because it has many side effects and is not obvious. 一些类实现了终结器〜ClassName(),但要避免这种情况,因为它有很多副作用并且不明显。

You can read an using statement as: 您可以将using语句读取为:

TestClass test = new TestClass();
try
{
      test.DoSomething();
}
finally
{
      test.Dispose();
}

You should always do it so long as the lifetime of the object is short enough that this is possible. 只要对象的生存期足够短,就应该始终这样做。 Sometimes you have to handle the cleanup separately because you have objects with a long lifetime that will persist long after the block of code is done. 有时,您必须单独处理清理,因为您的对象的生命周期很长,并且在代码块完成之后会持续很长时间。

There are three scenarios when an IDisposable object is created: 创建IDisposable对象的情况有以下三种:

  1. The object will be needed for a little while, but won't be needed after the current block of code exits. 该对象将需要一会儿,但在当前代码块退出后将不再需要。
  2. The object will be given to the caller of the current routine, which will then be responsible for it. 该对象将被提供给当前例程的调用者,由后者负责。
  3. The class which is responsible for the IDisposable object stores it in a field so it will be available for use in future method/property calls. 负责IDisposable对象的类将其存储在字段中,因此可以在以后的方法/属性调用中使用。

In scenario #1, use a "using" block to create the object; 在场景1中,使用“ using”块创建对象; its cleanup will be handled automatically. 它的清理将被自动处理。

In scenario #2, use a "try-finally" block with an "ok" variable that's set to "False" initially but is set to "True" at the end of the "try" or just before any return; 在场景2中,使用带有“ ok”变量的“ try-finally”块,该变量最初设置为“ False”,但在“ try”结束时或返回任何值之前设置为“ True”。 in the finally, if "oK" is false, call Dispose to ensure the partially-constructed object gets cleaned up. 最后,如果“ oK”为假,则调用Dispose以确保清理部分构造的对象。

In scenario #3, store the object in a field as soon as it's created, and define an IDisposable.Dispose method which will copy the value in the field to a variable, null out the field, and if the variable was non-null, Dispose it (if there's any possibility of multiple threads calling Dispose simultaneously, use Interlocked.Exchange to latch and clear the field). 在方案3中,将对象在创建后立即存储在字段中,并定义一个IDisposable.Dispose方法,该方法会将字段中的值复制到变量中,使该字段为空,如果该变量为非null,处理它(如果有多个线程同时调用Dispose的可能性,请使用Interlocked.Exchange锁存并清除该字段)。 Constructors should also be protected as would functions in scenario #2. 构造器也应该受到保护,就像方案2中的功能一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM