15

using(...) ステートメントは、try{} finally {} のシンタックス シュガーです。

しかし、次のような using ステートメントがあるとします。

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


}

ここで、このファイルを開くことで発生する可能性のある例外をキャッチしたいと考えています (環境によっては失敗する可能性があるという点で、これはかなりリスクの高いコードです)。コードがILにコンパイルされると、コードがJITされたときに繰り返しが削除されると思いますか?

ただし、ファイルを開くと発生する可能性のある例外をキャッチしたいと思います (したがって、using ステートメントのスコープ外で try-catch をラップする必要があります)。ブロックの中に。

これは、CLR がおそらく内部で行っていることに多くの繰り返しを追加しているように思えます。CLR は catch 句を追加しますか?

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

別の注意として、IDisposale を実装するすべての型は、管理されていないリソースの所有者ですか? 友人と話し合った結果、答えはノーでした。(私はまた、このフォーラムの使用セクションでいくつかのスレッドを読みました。いくつかの非常に優れた知識があります)。

4

5 に答える 5

7

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

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

于 2009-09-02T20:44:57.273 に答える
7

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

ただし、自分で行う場合は、正しく行うようにしてください。このUsingブロックは、変数がより早くコレクションの対象になるように、匿名スコープ ブロックも作成します。ブロックの最後に呼び出されるメソッドは、管理されていないリソースのみをクリーンアップするため.Dispose()オブジェクトが保持するメモリは少し長く残る可能性があります。これはおそらく大きな問題ではありませんが、念のため覚えておく価値があります。 Using

したがって、パターンを直接適応させるには、コードを次のようにする必要があります。

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

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

Using個人的には、サポートCatchFinallyブロックに拡張してほしいです。彼らはすでにコードの変換を実行しているので、これによってさらに複雑さが増すとは思えません。

于 2009-09-02T20:59:08.430 に答える
4

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

唯一のこと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();
    }
}

これを使用して、明示的に start と stop が呼び出されることに依存することなく、次のように時間を計ることができます。

using(Timer timer = new Timer())
{
    //do stuff
}
于 2009-09-02T20:40:15.363 に答える
4

using と try-finally の最大の違いは、using はDispose()メソッドを呼び出すだけであるということです。独自の finally ブロックを実装すると、ログなどの他のロジックを実行できますが、これは using には含まれません。

于 2009-09-02T20:42:01.070 に答える
3

このusing構文は、try/finallyブロックの省略形です。つまり、コンパイラは以下を生成します。

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

したがって、 がusing必要ない場合は使用するのが適切ですが、必要なcatch場合は通常の を使用する必要がありますtry/catch/finally

于 2009-09-02T20:47:36.863 に答える