web-dev-qa-db-ja.com

ステートメントとIDisposable.Dispose()の使用

コードがブロックを終了すると、.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()メソッドで異なることを実行できることを認識していることに注意してください。この質問は、usingステートメントがオブジェクトのDispose()メソッドを呼び出すのとまったく同じ結果を達成するかどうかに関するものです。

49

usingは基本的に次と同等です。

_try
{
  // code
}
finally
{
  obj.Dispose();
}
_

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

66
Brian Warshaw

Brian Warshawhere で述べているように、オブジェクトを確実に破棄するためのtryおよびfinallyブロックの単なる実装です。彼の答えに加えて、usingブロックは、returnを使用してscopeであってもオブジェクトが破棄されることを確認します。

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

カスタム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(); }
    }
}

outputは次のとおりです。

  • UsingReturn.Dispose()が呼び出されます!
  • UsingException.Dispose()が呼び出されます!
  • DisposeExtra.Dispose()が呼び出されます!
19
Saro Taşciyan
//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ステートメントがコンパイラーによって変換される方法です

9
hatchet

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

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

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

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

myThingが返されない場合にDisposedが取得されるようにします。 usingを「キャンセル破棄」メソッドとともに使用する方法があればいいのですが、そのようなものは存在しません。

6
supercat

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

Con.Open()
'do whatever

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

私はVB構文ではありませんが、C#では同等のコードは

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

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

3
jrummell

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

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

3

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

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

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

2
jglouie

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

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