57

コードがブロックを終了すると、.NETのusingステートメントIDisposableがオブジェクトのDispose()メソッドを呼び出すことを理解しています。

using声明は他に何かしますか?そうでない場合、次の 2 つのコード サンプルはまったく同じことを達成しているように見えます。

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

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

私が正しいことを確認したり、私が間違っていることを指摘したり、その理由を説明したりする人に、最良の回答を差し上げます。特定のクラスがメソッドで異なることを実行できることを認識していることを覚えておいてください。この質問は、ステートメントがオブジェクトのメソッドを呼び出すのとまったく同じ結果を達成するDispose()かどうかに関するものです。usingDispose()

4

9 に答える 9

80

using基本的には次のものと同等です:

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

Dispose()そのため、ブロック内のコードで未処理の例外がスローされた場合でも呼び出すことができるという利点もあります。

于 2012-06-11T16:52:54.030 に答える
20

ここでBrian Warshawが述べたように、オブジェクトが確実に破棄されるようにするための単純な実装tryとブロックです。finally彼の答えに加えて、 block は、 scopeを使用して内部に戻ったusing場合でも、オブジェクトが確実に破棄されるようにします。

私はかつてこれに興味があり、次のアプローチを使用してテストしました。

カスタム IDisposable テスト クラスとメイン

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();
}        

テストケースの実装

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(); }
    }
}

出力は次のとおりです。

  • UsingReturn.Dispose() が呼び出されます!
  • UsingException.Dispose() が呼び出されます!
  • DisposeExtra.Dispose() が呼び出されます!
于 2013-12-29T13:36:42.727 に答える
9
//preceeding code
using (con = new Connection()) {
    con.Open()
    //do whatever
}
//following code

は次と同等です (con の範囲が限定されていることに注意してください)。

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

これについては、http: //msdn.microsoft.com/en-us/library/yh598w02.aspxで説明されています。

using ステートメントを使用すると、オブジェクトのメソッドを呼び出しているときに例外が発生した場合でも、Dispose が確実に呼び出されます。オブジェクトを try ブロック内に配置してから、finally ブロック内で Dispose を呼び出すことによって、同じ結果を得ることができます。実際、これは using ステートメントがコンパイラによって変換される方法です。

于 2012-06-11T18:30:57.903 に答える
6

usingステートメントは構造よりも明確で簡潔であり、ブロックが呼び出されtry...finally{Dispose()}ずに終了することを許可したくないほとんどすべての場合に使用する必要があります。Dispose「手動」での廃棄の方がよい唯一の一般的な状況は、次の場合です。

  1. メソッドは、`IDisposable` を実装する場合と実装しない場合があるものを返すファクトリ メソッドを呼び出しますが、実装する場合は `Dispose` する必要があります (非ジェネリックな `IEnumerable.GetEnumerator()` で発生するシナリオ)。適切に設計されたファクトリ インターフェイスは、「IDisposable」を実装する型を返すか (おそらく、通常は「IEnumerator」の場合のように何もしない実装を使用)、呼び出し元が返されたオブジェクトを「破棄」する必要がないことを指定する必要があります。残念ながら、非ジェネリックな IEnumerable のような一部のインターフェイスは、どちらの基準も満たしていません。宣言された型が IDisposable を実装しているストレージの場所でのみ機能するため、このような場合に `using` をうまく使用できないことに注意してください。
  2. `IDisposable` オブジェクトは、ブロックが終了した後も存続することが期待されます (`IDisposable` フィールドを設定するとき、またはファクトリ メソッドから `IDisposable` を返すときによくあることです)。

ファクトリ メソッドからを返す場合IDisposableは、次のようなものを使用する必要があることに注意してください。

  ブールok = false;
  DisposableClass myThing;
  試す
  {
    myThing = 新しい DisposableClass();
    ...
    わかりました=真;
    myThing を返します。
  }
  最後に
  {
    もし (!ok)
    {
      if (myThing != null)
        myThing.Dispose();
    }
  }

返されない場合は確実myThingにd が返されるようにします。「破棄のキャンセル」メソッドと一緒Disposeに使用する方法があればいいのにと思いますが、そのようなものはありません。using

于 2012-06-11T19:06:24.190 に答える
5

2つの違いは、例外がスローされた場合

Con.Open()
'do whatever

Con.Dispose呼び出されません。

私はVBの構文について詳しくありませんが、C#では、同等のコードは次のようになります

try
{
    con = new Connection();
    // Do whatever
}
finally
{
    if (con != null) con.Dispose();
}
于 2012-06-11T16:52:38.787 に答える
3

Dispose()using ブロックは、例外がスローされた場合に 確実に呼び出されるようにします。

2 番目のサンプルはそれを行いません。

Con.Open()例外がスローされた場合、最初のケースでは呼び出されることが保証されCon.Dispose()ます。2 番目のケースでは、例外が伝播され、Con.Dispose()呼び出されません。

于 2012-06-11T16:52:31.997 に答える
3

このusingステートメントは、例外がスローされた場合にオブジェクトが破棄されることを保証します。finallyブロック内で dispose を呼び出すのと同じです。

于 2012-06-11T16:52:49.630 に答える
3

Using は、finally ブロックで Dispose を呼び出す try/finally で囲まれたブロックをラップします。これにより、例外が発生した場合でも Dispose が呼び出されることが保証されます。

安全上の理由から、ほとんどすべての場合にusing を使用する必要があります

于 2012-06-11T16:54:09.163 に答える
1

メモリが機能する場合、 using は、オブジェクトを囲むコードブロックがどのようにオブジェクトを終了するかに関係なく、オブジェクトが破棄されることを保証します。これは、ブロックを try...finally ブロックで囲み、使用された変数が null かどうかをチェックし、null でない場合は破棄することによって行われます。例外がスローされた場合、スタックをバブルアップできます。それ以外は、null 以外の使い捨てオブジェクトの破棄を保証するだけです。

try
{
  var myDisposable = new DisposableObject();
  myDisposable.DoSomething();
}
finally
{
  if (myDisposable != null)
    ((IDisposable)myDisposable).Dispose();
}
于 2012-06-11T17:42:50.847 に答える