7

私は c# にはやや慣れていませんが、スクリプト言語には慣れています。私は「使用する」という考え方が好きです。オブジェクトをインスタンス化し、必要な限りそのスコープ内で操作し、目的が達成されたらそれ自体を破棄します。

でも、私にとっては不自然です。人々がそれを使った例を見せてくれたとき、私はそれが仕事に適したツールであると認識していますが、自分のプログラミングでそれを使って問題を解決することは決して思い浮かびません.

使用するのに適した場所を認識する方法usingと、それを try-catch ブロックと組み合わせて使用​​する方法。それらはブロック内に入りますか、それとも通常、using ステートメントを try ブロック内で囲みますか?

4

11 に答える 11

18

usingを実装する型でのみ使用できますIDisposableDispose()エラーが発生した場合でも、メソッドが呼び出されることが保証されます。

このコード:

using (MyDisposableType x = new MyDisposableType())
{  
    // use x
}

これと同等です:

MyDisposableType x = new MyDisposableType();
try
{  
    // use x
}
finally 
{ 
    x.Dispose(); 
}
于 2009-04-03T07:09:06.533 に答える
9

私は try/catch ブロックを書くことはめったにありません。ほとんどの例外は、スタックの一番上 (近く) までスローされます。try/catch ブロックが必要な場合、usingステートメントの内側と外側で特に一貫性があるかどうかはわかりません。例外処理コードの実行前または実行後にリソースを破棄するかどうかによって異なります。

いつステートメントを書くべきかについて質問している場合using-実装するオブジェクトを「所有」しIDisposable(継承を介して直接的または間接的に)、その寿命を制御するときはいつでも。これは通常、ファイル ハンドルやネットワーク接続などの管理されていないリソースを使用するオブジェクトです。それは常に非常に明白というわけではありませんが、経験を通して学びます。IO に関係するほとんどすべてが使い捨てになり、Windows ハンドル (フォントなど) も同様です。

于 2009-04-03T07:12:42.423 に答える
3

私はそれを「タイプが IDisposable を実装するたびに使用し、この特定のインスタンスはもう必要ない」と考えていました。

于 2009-04-03T07:13:48.457 に答える
2

独自のデザインでクリエイティブに使用する方法を知りたい場合は、独自のコードを調べて、囲んでいるブロックが終了する前に特定のコードを実行する必要がある状況を調べてください。これらは、try/finallyまたはusingが役立つ状況です。

特に、すべての例外をキャッチしてこれを達成しようとした場合は、代わりにtry/ finallyorに変更する必要があります。using

パターンが数回発生する場合は、パターンをキャプチャするために実装するクラスを作成し、ステートメントIDisposableでパターンを呼び出すことができます。usingただし、1 回限りのように見える特定のケースがある場合は、try/を使用してfinallyください。

この 2 つは非常によく似ており、 -は/usingで指定されていますが、 しかない場合でも、/を自分で構築できます。tryfinallyusingtryfinally

public class DisposeAnything : IDisposable
{
    public Action Disposer;

    public void Dispose()
    {
        Disposer();
    }
}

今、あなたは言うことができます:

using (new DisposeAnything 
      {
          Disposer = () => File.Delete(tempFileName) 
      })
{
    // blah
}

これは次と同じです:

try
{
    // blah
}
finally
{
    File.Delete(tempFileName);
}

スコープを離れたときに実行するコードを取得する方法と考えてください。

于 2009-04-03T07:22:04.523 に答える
1

クラスが IDisposable を実装している場合、それにはおそらく正当な理由があります。したがって、IDisposable を実装するクラスは破棄する必要があります。

于 2009-04-03T07:42:31.337 に答える
1

これが「シンタックス シュガー」と呼ばれるものであり、try/finally dispose コンストラクトと同じ IL を生成することを考えると、このようなコードを「簡略化」するための本当に良い方法です。

ファイルやグラフィックスオブジェクトなどのリソースへのアクセスなど、使い捨てオブジェクトが頻繁に使用されるコードのセクションを簡素化するために使用するのが好きで、リソースオブジェクトの破棄を処理することを忘れないようにしたい.

于 2009-04-03T07:58:55.683 に答える
1

ミッチが言ったこと、プラス..

try..catch ブロックの外側または内側で using ステートメントを使用できます。これは、何を達成しようとしているかによって異なります。たとえば、回復する予定の特定のオブジェクトを使用しているときに、何かが例外をスローすることを合理的に期待しているかどうかによって異なります。 .

同様に、必要に応じて、finally ブロックで IDisposable を実装するオブジェクトを Dispose することもできます。

于 2009-04-03T07:13:09.910 に答える
1

確定的なオブジェクトの破棄が必要な場合は、using を使用します。たとえば、ファイルを開くと、ファイルはロックされます。他のプログラムがアクセスできるように、できるだけ早くファイルを閉じたい場合がよくあります。using を使用せず、次のように書く場合:

System.IO.FileStream writeStream = new System.IO.FileStream( fileName, System.IO.FileMode.OpenOrCreate ) );
System.IO.BinaryWriter writer = new System.IO.BinaryWriter( writeStream ) );
//do smth 

そして、「do smth」中に例外が発生し、ファイルで動作しているオブジェクトが実際にいつ破棄され、ファイルが閉じられるかわかりません。using を使用すると、 usingステートメント ブロックを離れると、直接または例外を介して、usingステートメント内のオブジェクトが IDisposable::Dispose を呼び出すことによって破棄されることが確実にわかります。

using( System.IO.FileStream writeStream = new System.IO.FileStream( fileName, System.IO.FileMode.OpenOrCreate ) ) {
    using( System.IO.BinaryWriter writer = new System.IO.BinaryWriter( writeStream ) ) {
        //do stmth
    }
}
于 2009-04-03T07:14:01.437 に答える
1

using を try/catch ブロック内で囲むことができ、try/catch ブロックを using 内で囲むことができます。

DBConnection と DBCommands を使用してデータベース操作を行っている場合は、次のように使用すると便利です。

using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand(sql, conn))
{
  // do something here
}

using ブロックを離れると、コマンドが破棄され、接続が閉じられます。

于 2009-04-03T07:14:37.397 に答える
1

ミッチの言うことは正しい。したがって、using の主な用途は、try/catch または try/finally ステートメントをコーディングすることなく、IDisposable オブジェクトを確実に破棄することです。

さて、興味深いと思われるより高度な使用法があります。using ステートメントを使用すると、コンパイラは try/finally を生成し、生成する finally 内で Dispose() の呼び出しも生成します。この Dispose() メソッドを「フック」として使用して、必要なことを何でも実行できます...リソースの解放に関連する必要はありません。

たとえば、Jeffrey Richter は、彼が作成したタイマー オブジェクトでこれを使用しています。あなたはそれでこのようなことをすることができます(概念のみ):

using(var x = new Timer())
{
  // Do the operation you want timed
}

// Now, the timer has been stopped, because the 
// compiler-generated call to Dispose() has already 
// occurred, and Jeffrey uses Dispose() to stop 
// the timer.
于 2009-04-03T07:16:26.610 に答える
0

Dispose メソッドが通知を行うことが知られている場合、プログラマーは無意味に思えるのでわざわざ呼び出さないことに気付きました。ただし、オブジェクトが IDisposable を実装している場合は、(うまくいけば) 理由があり、そのオブジェクトの将来のバージョンでは実際に Dispose メソッドにコードが含まれている可能性があるため、常に呼び出します。

于 2009-04-03T08:00:31.747 に答える