コードがブロックを終了すると、.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()
メソッドを呼び出すのとまったく同じ結果を達成するかどうかに関するものです。
using
は基本的に次と同等です。
_try
{
// code
}
finally
{
obj.Dispose();
}
_
そのため、未処理の例外がブロック内のコードでスローされた場合でも、Dispose()
を呼び出す利点もあります。
Brian Warshawが here で述べているように、オブジェクトを確実に破棄するための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は次のとおりです。
//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ステートメントがコンパイラーによって変換される方法です。
using
ステートメントはtry...finally{Dispose()}
構文よりも明確で簡潔であり、Dispose
なしでブロックを終了させたくないほとんどすべての場合に使用する必要があります。呼ばれています。 「手動」廃棄がより良い唯一の一般的な状況は次の場合です。
ファクトリメソッドからIDisposable
を返すときは、次のようなものを使用する必要があることに注意してください。
bool ok = false; DisposableClass myThing; try { myThing = new DisposableClass(); ... ok = true; return myThing; } 最終的に { if(!ok) { if(myThing!= null) myThing.Dispose(); } }
myThing
が返されない場合にDispose
dが取得されるようにします。 using
を「キャンセル破棄」メソッドとともに使用する方法があればいいのですが、そのようなものは存在しません。
2つの違いは、例外がスローされた場合
Con.Open()
'do whatever
Con.Dispose
は呼び出されません。
私はVB構文ではありませんが、C#では同等のコードは
try
{
con = new Connection();
// Do whatever
}
finally
{
if (con != null) con.Dispose();
}
using
ステートメントは、例外がスローされるイベントでオブジェクトが破棄されることを保証します。 finally
ブロックでdisposeを呼び出すのと同じです。
を使用すると、囲まれたブロックがtry/finallyでラップされ、finallyブロックでDisposeが呼び出されます。これにより、例外が発生した場合でもDisposeが呼び出されます。
安全上の理由から、ほとんどすべての場合にsingを使用する必要があります
Usingブロックは、例外がスローされた場合にDispose()
が確実に呼び出されるようにします。
2番目のサンプルはそれを行いません。
Con.Open()
が例外をスローした場合、最初のケースでは、Con.Dispose()
が呼び出されることが保証されます。 2番目の場合、例外は伝播し、Con.Dispose()
は呼び出されません。
メモリが機能する場合、使用することで、オブジェクトを囲むコードブロックがどのようにオブジェクトを終了するかに関係なく、オブジェクトが破棄されることが保証されます。これを行うには、ブロックをtry ... finallyブロックで囲み、sed変数がnullかどうかを確認し、nullでない場合は破棄します。例外がスローされた場合、スタックをバブルアップできます。それ以外は、null以外の使い捨てオブジェクトの廃棄を保証するだけです。
try
{
var myDisposable = new DisposableObject();
myDisposable.DoSomething();
}
finally
{
if (myDisposable != null)
((IDisposable)myDisposable).Dispose();
}