2009-09-02 16 views
15

using(...)文はtry {} finally {}の構文砂糖です。ステートメントとtry-catch()を使用する - 最後に繰り返しますか?

しかし、私はその後、以下のようにusingステートメントを使用している場合:

using (FileStream fs = File.Open(path)) 
{ 


} 

は今、私はそれが原因に失敗することができるという点で、このファイルを開くと原因(これはかなりリスクの高いコードであることができると例外をキャッチしたいです環境)、しかし、私はtry-catchを書く場合は繰り返しではないでしょうか?コードがILにコンパイルされると、コードがJITされたときに反復が削除されると思いますか?

しかし、ファイルを開くことで例外が発生する可能性があります(使用する文の範囲外でtry-catchを囲む必要があります)。また、使用するブロック内で何を行うにしても例外があります。ブロック内のtry-catch。

これは、CLRがおそらく内部で何を行うかについて、私は多くの繰り返しを追加しているようです。 CLRはcatch節を追加しますか?

私の同僚は、usingステートメントが面倒だと主張しました(しかし、これは、私が非常に素早く変更する必要があるため、ハードコーディングしているために1行が少し長くなっていたためです。ベース)。同僚はusingステートメントを使用しませんが、usingステートメントとtry-finally/try-catch-finallyの間に機能的な違いはありますか?私は、WCFサービスが、最終的に値を返すことについてのよく知られていないコーナーケースを持っているこのケースを見ました。解決策はチェックブロックを使用することでした。これはC#のようなものですか?

さらに、管理対象外のリソースのIDisposale所有者を実装するすべてのタイプはありますか?私の友人との討論は答えがノーだと指摘した。 (私はこのフォーラムの使用セクションのいくつかのスレッドも読んでおり、そこには非常に良い知識があります)。

答えて

7

本当にしたい場合は、いくつかの例外を処理する必要がある場合は、自分でパターンを実装することができます。個人的には、try/catchブロックでの使用を単にラップする方が簡単です(もっと重要なのはもっと明確です)。

しかし、あなたがそれを自分で行う場合は、正しいことを確認してください。また、Usingブロックは匿名スコープブロックを作成して、変数がより早く収集対象となるようにします。 Usingブロックの最後に呼び出される.Dispose()メソッドは、のリソースがアンマネージ個だけクリーンアップされるため、オブジェクトが保持する任意のメモリが少し長くハングすることがあります。それはおそらく大きな懸念ではありませんが、念のために覚えておく価値があります。

ので、パターンの直接の適応を行うには、あなたのコードをよりこのように見える必要があります。個人的に

{ 
    FileStream fs; 
    try 
    { 
     fs = File.Open(path); 

    } 
    catch (FileNotFoundException e) { /* ... */ } 
    catch (IOException e) { /* ... */ } 
    catch (Exception e) {/* ... */} 
    finally 
    { 
     if (fs != null) fs.Dispose(); 
    } 
} 

、私はUsingCatchFinallyブロックをサポートするように拡張してもらいたいです。彼らは既にコード上で変換を行っているので、このように複雑さが増すことはありません。

+0

最後にサポートを使用していますか?匿名のスコープブロックを使用して、どこで使用したのですか?私はこれについてもっと知りたいです。したがって、私が使用しているブロック(FileSream.Open()など)でファイルを開くと、この例外はバブルアップします。 usingステートメントがtry/finallyを実装している場合、catch/catchだけをtry/catchでラップする必要があります。 – dotnetdev

4

ステートメント中に発生する可能性があるさまざまな例外を明示的に処理する必要がある場合は、usingtry/catch/finallyに置き換えて、最後にDispose()を明示的に呼び出します。または、usingブロックの周りにtry/catchを置くことで、例外的な状況と廃棄の確実性を区別することができます。

usingは、ブロック内に例外がスローされた場合でも確実にDispose()が呼び出されます。これは、一般的なtry/[catch]/finally構造の非常に限られた、非常に特殊な実装です。

重要なことは、これらのオプションのどれもが実際に影響を及ぼさないということです。あなたが必要としている限り、読解可能で分かりやすく、誰が気にしますか?それはボトルネックか何かになる余分な試みのようではありません!

あなたの最後の質問に答えて - いいえ、IDisposableは必ずしも実装者が管理されていないリソースを扱うことを意味するとは限りません。それはそれよりはるかに簡単で一般的なパターンです。ここで有用な一例です:

public class Timer : IDisposable 
{ 
    internal Stopwatch _stopwatch; 
    public Timer() 
    { 
     this._stopwatch = new Stopwatch(); 
     this._stopwatch.Start(); 
    } 

    public void Dispose() 
    { 
     this._stopwatch.Stop(); 
    } 
} 

我々が明示的に開始に依存しており、使用して呼び出されて停止させることなく、時間のものにこれを使用することができます。

using(Timer timer = new Timer()) 
{ 
    //do stuff 
} 
4

使用との最大の違いは、しようと、最終的です使用するとDispose()メソッドのみが呼び出されます。独自のブロックを実装する場合は、他のロジック、例えばロギングなどを行うことができます。これは、使用には含まれません。

+0

+1のために短く –

7

私の好みは、usingステートメントを保持し、try/catchでラップすることです。外側のtry/catchはDispose()を無視しながら、あなたが監視する必要のある例外をキャッチします。これは後でtry/catchを(呼び出し関数のように)別の場所に移動するためにリファクタリングする必要があります。

あなたのIDisposableに関する限り、誰でも好きな理由でこれを実装できます。それが管理されていないリソースに限定されるという技術的な理由はありません。 (の場合は、コードのアンマネージドリソースに限定する必要があるかどうかは別の質問です)。

3

using構成は、ブロックtry/finallyの省略形です。

FileStream fs = null; 
try 
{ 
    fs = File.Open(path); 
    // ... 
} 
finally 
{ 
    if (fs != null) 
     fs.Dispose(); 
} 

だから、あなたが catchを必要としない場合 usingを使用することが適当であるが、あなたはそれから行う場合は、通常の try/catch/finallyを使用する必要があります。それは、コンパイラが生成します。

+2

'試して'/'キャッチ'で '使用する '自体をラップすることは何も問題ありません。最終的に見ていなくても、ブロックが終了した後にどのリソースが解放されたかが即座に明らかになるため、「最終的に」よりもはっきりしています。 –

関連する問題