6

には using ステートメントを使用しSqlConnectionます。プールへの接続を解放するだけの Dispose() の呼び出しを強制するため、パフォーマンスが向上します。

しかし、using で作成したオブジェクトは再定義できないことに気付きました。私はこのようにすることはできません:

   using (SqlConnection connection = new SqlConnection(connectionString))
   {
       connection.Open();
       //...
       connection = new SqlConnection(connectionString2);
       //...
       connection = new SqlConnection(connectionString3);
   }

using を置き換えて、次のようなことができるかどうか疑問に思っていました。

 {
       SqlConnection connection = new SqlConnection(connectionString);

       connection.Open();
       //...
       connection = new SqlConnection(connectionString2);
       //...
       connection = new SqlConnection(connectionString3);
 }

最後のブレースSqlConnectionの後はアクセスできません。}オブジェクトがスコープ外になるとすぐに Dispose() が呼び出されますか?

4

7 に答える 7

13

いいえ、2 番目の例では自動的にクリーンアップされません (実際、このコードでは、いくつかの接続が開いたままになります)。

それだけでなく、usingブロック内で例外がスローされると、自動クリーンアップが失われます。usingブロックは次のように分解されることに注意してください。

SqlConnection connection = new SqlConnection(connectionString);
try
{
    connection.Open();
    // Do work
}
finally
{
    connection.Dispose();
}

実際に異なる接続を使用していて、各接続がブロックの最後で破棄されている場合は、いくつかの using ブロックを使用します。

using(SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    // Do Work
}

// First connection is disposed

using(SqlConnection connection = new SqlConnection(connectionString2))
{
    // Do More Work
}

// Second connection is disposed

using(SqlConnection connection = new SqlConnection(connectionString3))
{
    // Do More Work
}

// Last connection is dipsosed
于 2010-09-03T12:55:00.540 に答える
8

このステートメントは、内で初期化されたオブジェクトusingを呼び出す構文糖衣であるため、例のように単純に置き換えることはできません。Dispose()

usingステートメント内で使用できるオブジェクトは、 を実装するオブジェクトだけであることに注意してください。IDisposableこれにより、 を確実Disposeに呼び出すことができます。

この記事で説明しているように、コンパイラはこれを次のように変換します

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

}

これに:

MyResource myRes= new MyResource();
try
{
    myRes.DoSomething();
}
finally
{
    if (myRes!= null)
        ((IDisposable)myRes).Dispose();
}

したがって、この構造を複製しない限り、同じ動作は得られません。

さらに、例のように変数を再利用することは悪い習慣です。コードを読んだ人は、実際には接続 2 または 3 を見ているのに、接続 1 を見ていると思うかもしれません。非常に混乱し、将来あらゆる種類の問題を引き起こす可能性があります。

于 2010-09-03T12:54:17.103 に答える
3

いいえ、使用すると、ブレースだけでは得られない特定のクリーンアップ構造が作成されます。

Reflector を使用して IL を見ると、ターゲットの using ブロックの最後に Dispose の呼び出しが追加されています。

    L_0006: newobj instance void [System.Data]System.Data.SqlClient.SqlConnection::.ctor(string)
L_000b: stloc.0 
L_000c: nop 
L_000d: nop 
L_000e: leave.s L_0020
L_0010: ldloc.0 
L_0011: ldnull 
L_0012: ceq 
L_0014: stloc.1 
L_0015: ldloc.1 
L_0016: brtrue.s L_001f
L_0018: ldloc.0 
**L_0019: callvirt instance void [mscorlib]System.IDisposable::Dispose()**
L_001e: nop 
L_001f: endfinally 

これは、using ブロック内で新しい接続を作成して変数に割り当てることができない理由を説明しています。これを行うと、元の参照がハングして未処理のままになります。

于 2010-09-03T12:51:30.250 に答える
3

いいえ、閉じ中括弧の後には呼び出されません。手動で呼び出すか、usingステートメントを使用する必要があります。

dispose を実行しない場合は、ファイナライズが呼び出されたときに実行されます。そして、ここに2つの問題があります

  • Finalize メソッドを実行すると、パフォーマンスが低下します。Dispose メソッドがオブジェクトをクリーンアップする作業を既に行っている場合、ガベージ コレクターがオブジェクトの Finalize メソッドを呼び出す必要はありません (適切に実装されている場合、Dispose メソッドは、破棄するオブジェクトの SuppressFinalize メソッドを呼び出す必要があります)。 )。 (MSDN)
  • ファイナライズが自動的に呼び出されて実行できなかった瞬間を制御することはできません (たとえば、クラッシュのため)。
于 2010-09-03T12:51:40.230 に答える
3
using(foo)
{
  // stuff
}

...は、次のように変換される少しの砂糖です。

try
{
  // stuff
}
finally
{
  foo.Dispose()
}

一方:

{
  // stuff
}

...何にも翻訳されません。それはただ:

{
  // stuff
}

:D

編集:編集時にフォーマットを破棄しないでください:(

于 2010-09-03T12:57:27.853 に答える
2

いいえ、できません。少なくとも C# では。

ただし、1 つの using ステートメント内でさまざまな使い捨てオブジェクトを作成できます。

   using (SqlConnection connection1 = new SqlConnection(connectionString1),
          connection2 = new SqlConnection(connectionString2),
          connection3 = new SqlConnection(connectionString3))
   {
       connection1.Open();
       //...
       connection2.Open();
       //...
       connection3.Open();
   }

C++/CLI では、使い捨てクラスをスタックのような機能で使用できます。

void MyClass::Foo()
{

{
  SqlConnection connection(connectionString);
  //connection still allocated on the managed heap
  connection.Open();
  ...
  //connection will be automatically disposed 
  //when the object gets out of scope
} 


{
  SqlConnection connection(connectionString2);
  connection2.Open();
  ...
}

}
于 2010-09-03T13:35:03.003 に答える
1

私も最初はこれも考えました...しかし、どうやらusingブロックが終了する.Dispose()と、オブジェクトに対して呼び出されます。これは、オブジェクトをスコープから外すのとは異なります。C#はガベージコレクションされた言語であるため、オブジェクトが実際にクリーンアップされるまでに時間がかかる場合があります。ブロックは、using例外に関係なく、すぐに破棄されることを保証します。

于 2010-09-06T08:06:44.933 に答える