C# 使用语句与 IDisposable.Dispose()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10984336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 16:02:16  来源:igfitidea点击:

Using statement vs. IDisposable.Dispose()

c#.netvb.netusingidisposable

提问by oscilatingcretin

It has been my understanding that the usingstatementin .NET calls an IDisposableobject's Dispose()method once the code exits the block.

我的理解是,一旦代码退出块,.NET中的using语句就会调用IDisposable对象的Dispose()方法。

Does the usingstatement do anything else? If not, it would seem that the following two code samples achieve the exact same thing:

请问using声明要做什么吗?如果没有,以下两个代码示例似乎实现了完全相同的事情:

Using Con as New Connection()
    Con.Open()
    'do whatever '
End Using

Dim Con as New Connection()
Con.Open()
'do whatever '
Con.Dispose()

I will give the best answer to whoever confirms that I am correct or points out that I am wrong and explains why. Keep in mind that I am aware that certain classes can do different thingsin their Dispose()methods. This question is about whether or not the usingstatement achieves the exact same result as calling an object's Dispose()method.

我会为确认我正确或指出我错并解释原因的人给出最佳答案。请记住,我知道某些类可以在它们的Dispose()方法中做不同的事情。这个问题是关于该using语句是否获得与调用对象Dispose()方法完全相同的结果。

采纳答案by Brian Warshaw

usingis basically the equivalent of:

using基本上相当于:

try
{
  // code
}
finally
{
  obj.Dispose();
}

So it also has the benefit of calling Dispose()even if an unhandled exception is thrown in the code within the block.

因此,Dispose()即使在块内的代码中抛出未处理的异常,它也具有调用的好处。

回答by jglouie

The using block makes sure that Dispose()is called if an exception is thrown.

using 块确保Dispose()在抛出异常时调用它。

Your second sample does not do that.

你的第二个样本没有这样做。

If Con.Open()threw an exception, in the first case you are guaranteed that Con.Dispose()is called. In the second case, the exception propagates up and Con.Dispose()will not be called.

如果Con.Open()抛出异常,在第一种情况下,您可以保证Con.Dispose()被调用。在第二种情况下,异常Con.Dispose()会向上传播并且不会被调用。

回答by Eric J.

The difference between the two is that, if an Exception is thrown in

两者的区别在于,如果抛出异常

Con.Open()
'do whatever

Con.Disposewill not be called.

Con.Dispose不会被调用。

I'm not up on VB syntax, but in C#, the equivalent code would be

我不了解 VB 语法,但在 C# 中,等效代码是

try
{
    con = new Connection();
    // Do whatever
}
finally
{
    if (con != null) con.Dispose();
}

回答by jrummell

The usingstatement guarantees that the object is disposed in the event an exception is thrown. It's the equivalent of calling dispose in a finallyblock.

using语句保证在抛出异常时处理对象。这相当于在finally块中调用 dispose 。

回答by Panagiotis Kanavos

Using wraps the enclosed block in a try/finally that calls Dispose in the finally block. This ensures that Dispose will be called even if an exception occurs.

Using 将封闭块包装在 try/finally 中,在 finally 块中调用 Dispose。这确保即使发生异常也会调用 Dispose。

You should use usingin almost all cases, for safety reasons

出于安全原因,您应该在几乎所有情况下使用using

回答by Mike Hofer

If memory serves, using is a guarantee that an object is disposed of regardless of how the block of code it surrounds exits it. It does this by surrounding the block in a try...finally block, and checking the usedvariable for nullness, and then disposing of it if it is not null. If an exception was thrown, it's allowed to bubble up the stack. Aside from that, all it does is guarantee disposal of non-null disposable objects.

如果内存有用, using 是一个保证,无论对象周围的代码块如何退出它,对象都会被处理。它通过在 try...finally 块中包围块来实现这一点,并检查使用的变量是否为空,如果它不为空则将其处理掉。如果抛出异常,则允许在堆栈中冒泡。除此之外,它所做的只是保证处理非空的一次性对象。

try
{
  var myDisposable = new DisposableObject();
  myDisposable.DoSomething();
}
finally
{
  if (myDisposable != null)
    ((IDisposable)myDisposable).Dispose();
}

回答by hatchet - done with SOverflow

//preceeding code
using (con = new Connection()) {
    con.Open()
    //do whatever
}
//following code

is equivalent to the following (note the limited scope for con):

等效于以下内容(注意 con 的有限范围):

//preceeding code
{
    var con = new Connection();
    try {
        con.Open()
        //do whatever
    } finally {
        if (con != null) con.Dispose();
    }
}
//following code

This is described here: http://msdn.microsoft.com/en-us/library/yh598w02.aspx

这在这里描述:http: //msdn.microsoft.com/en-us/library/yh598w02.aspx

The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler.

using 语句确保 Dispose 被调用,即使在您调用对象的方法时发生异常。您可以通过将对象放在 try 块中,然后在 finally 块中调用 Dispose 来获得相同的结果;事实上,这就是编译器如何翻译 using 语句

回答by supercat

A usingstatement is clearer and more concise than a try...finally{Dispose()}construct, and should be used in nearly all cases where one does not want to allow a block to exit without Disposebeing called. The only common situations where "manual" disposal would be better would be when:

一个using说法是不是更清晰和更简洁的try...finally{Dispose()}构造,并应在几乎所有情况下,人们不希望允许退出块没有被使用Dispose被调用。“手动”处理会更好的唯一常见情况是:

  1. A method calls a factory method which returns something that may or may not implement `IDisposable`, but which should be `Dispose`d if it does (a scenario which occurs with non-generic `IEnumerable.GetEnumerator()`). Well-designed factory interfaces should either return a type that implements `IDisposable` (perhaps with a do-nothing implementation, as is typically the case of `IEnumerator`) or else specify callers are not expected to `Dispose` the returned object. Unfortunately, some interfaces like non-generic `IEnumerable` satisfy neither criterion. Note that one cannot very well use `using` in such cases, since it only works with storage locations whose declared type implements `IDisposable`.
  2. The `IDisposable` object is expected to live even after the block is exited (as is often the case when setting an `IDisposable` field, or returning an `IDisposable` from a factory method).
  1. 一个方法调用一个工厂方法,它返回的东西可能会或可能不会实现`IDisposable`,但是如果它实现了,它应该是`Dispose`d(发生在非通用`IEnumerable.GetEnumerator()`的情况)。设计良好的工厂接口应该要么返回一个实现`IDisposable` 的类型(可能是一个什么都不做的实现,就像`IEnumerator` 的典型情况),或者指定调用者不应该`Dispose` 返回的对象。不幸的是,像非通用的“IEnumerable”这样的接口不满足这两个标准。请注意,在这种情况下不能很好地使用 `using`,因为它只适用于声明类型实现 `IDisposable` 的存储位置。
  2. 即使在块退出后,“IDisposable”对象也有望继续存在(通常在设置“IDisposable”字段或从工厂方法返回“IDisposable”时就是这种情况)。

Note that when returning an IDisposablefrom a factory method, one should use something like the following:

请注意,IDisposable从工厂方法返回 an 时,应使用以下内容:

  bool ok = false;
  DisposableClass myThing;
  try
  {
    myThing = new DisposableClass();
    ...
    ok = true;
    return myThing;
  }
  finally
  {
    if (!ok)
    {
      if (myThing != null)
        myThing.Dispose();
    }
  }

to ensure that myThingwill get Disposed if it doesn't get returned. I wish there was a way to employ usingalong with some "cancel Dispose" method, but no such thing exists.

确保如果没有返回,myThing它将得到Disposed 。我希望有一种方法可以using与一些“取消处理”方法一起使用,但不存在这样的东西。

回答by Saro Ta?ciyan

As Brian Warshawstated in hereit's simply an implementation of tryand finallyblock to make sure object is disposed. Adding to his answer, usingblock also makes sure that the object is disposed even if you returninside using scope.

正如Brian Warshaw这里所说的,它只是一个tryfinally块的实现,以确保对象被释放。添加到他的回答中,using即使您使用scope返回内部,block 也可以确保对象被释放。

I was once curious about this myself and tested it out using the following approach:

我曾经对此感到好奇,并使用以下方法对其进行了测试:

Custom IDisposable test class and Main

自定义 IDisposable 测试类和 Main

private class DisposableTest : IDisposable
{
    public string Name { get; set; }

    public void Dispose() { Console.WriteLine("{0}.Dispose() is called !", Name); }
}

public static void Main(string[] args)
{
    try
    {
        UsingReturnTest();
        UsingExceptionTest();                
    }
    catch { }

    try
    {
        DisposeReturnTest();
        DisposeExceptionTest();                
    }
    catch { }

    DisposeExtraTest();

    Console.ReadLine();
}        

Test cases implementation

测试用例实现

private static string UsingReturnTest()
{
    using (DisposableTest usingReturn = new DisposableTest() { Name = "UsingReturn" })
    {
        return usingReturn.Name;
    }
}

private static void UsingExceptionTest()
{
    using (DisposableTest usingException = new DisposableTest() { Name = "UsingException" })
    {
        int x = int.Parse("NaN");
    }
}

private static string DisposeReturnTest()
{        
    DisposableTest disposeReturn = new DisposableTest() { Name = "DisposeReturn" };
    return disposeReturn.Name;
    disposeReturn.Dispose(); // # IDE Warning; Unreachable code detected
}

private static void DisposeExceptionTest()
{
    DisposableTest disposeException = new DisposableTest() { Name = "DisposeException" };
    int x = int.Parse("NaN");
    disposeException.Dispose();
}

private static void DisposeExtraTest()
{
    DisposableTest disposeExtra = null;
    try
    {
        disposeExtra = new DisposableTest() { Name = "DisposeExtra" };
        return;
    }
    catch { }
    finally
    {
        if (disposeExtra != null) { disposeExtra.Dispose(); }
    }
}

And the outputis:

输出是:

  • UsingReturn.Dispose() is called !
  • UsingException.Dispose() is called !
  • DisposeExtra.Dispose() is called !
  • 调用 UsingReturn.Dispose() !
  • 调用 UsingException.Dispose() !
  • DisposeExtra.Dispose() 被调用!