web-dev-qa-db-ja.com

C#で "using"を使用して例外をキャッチする方法

このコードを考えると:

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandText = "...";
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // ...
            }
        }
    }
}

私はデータアクセス用のtry/catch/finallyブロックを作成することに慣れていますが、これを行うためのはるかに単純な方法のように見える「使用」にさらされています。ただし、発生する可能性のある例外をキャッチする方法を理解しようとしています。

例外をキャッチする方法の例を教えてください。

編集して追加:

「使用」は、try/catch/finallyブロックの代わりになると私は信じています。を使用しても例外がキャッチされないことを理解しています。これはどのように置き換えられるのでしょうか?

31
GregD

usingは例外をキャッチするように設計されていません。破棄する必要のあるオブジェクトをtry/finallyで簡単にラップできるように設計されています。例外をキャッチして処理する必要がある場合は、それを完全なtry/catch/finallyに展開するか、包含try /を配置する必要があります全体のcatch


あなたの編集に答えるために(usingtry/catch/finallyの代わりです)いいえ、そうではありません。使い捨てリソースを使用する場合、ほとんどの場合、例外をそこで処理することはありません。そのため、通常、実行できる有用なことは何もないためです。したがって、何をしようとしているかに関係なく、リソースが確実にクリーンアップされるようにする便利な方法を提供します。

通常、使い捨てリソースを処理するコードは低レベルで機能しているため、失敗時の正しいアクションを決定できません。そのため、例外は、実行するアクション(再試行、失敗、ログなど)を決定できる呼び出し元に伝達されます。 。)。使い捨てリソースでcatchブロックを使用する傾向がある唯一の場所は、例外を変換する場合(つまり、データアクセスレイヤーが実行していること)です。

58
Greg Beech

すべてのusingステートメントをtry/catchにラップします。他の誰もが言ったように、使用はIDisposableインターフェースを実装するクラスをクリーンアップするためです

try
{

 using (var conn = new SqlConnection("..."))
 {
    conn.Open();
    using (var cmd = conn.CreateCommand())
    {
        cmd.CommandText = "...";
        using (var reader = cmd.ExecuteReader())
        {
            while (reader.Read())
            {
                // ...
            }
        }
    }
 }
}
catch(Exception ex)
{
//Handle, log, rethrow exception
}
12
Chuck Conway
using (var cmd = new SqlCommand("SELECT * FROM Customers"))
{
    cmd.CommandTimeout = 60000;
    ...
}

の構文糖

var cmd = new SqlCommand("SELECT * FROM Customers");
try
{
    cmd.CommandTimeout = 60000;
    ...
}
finally
{
    if (cmd != null)
        cmd.Dispose();
}

したがって、「使用する」はtry/catch/finallyの代わりになると人々が言っ​​ているときは、長い形式を使用する必要があるが、catchブロックに追加する必要があることを意味しています。

var cmd = new SqlCommand("SELECT * FROM Customers");
try
{
    cmd.CommandTimeout = 60000;
    ...
}
catch (Exception ex)
{
    ...//your stuff here
}
finally
{
    if (cmd != null)
        cmd.Dispose();
}
12
RogueBadger

例外をキャッチしたい場合は、try/catch/finallyを使用することをお勧めします。 .Dispose()呼び出しをfinallyブロックに入れるだけです。

7
Kevin Tighe

ステートメントの使用は、例外とは関係ありません。ブロックを使用すると、ブロックを終了するときに、ブロックを使用しているオブジェクトのDisposeが確実に呼び出されます。 I.E:

using(SqlConnection conn = new SqlConnection(conStr))
{
   //use conn
}//Dispose is called here on conn.

接続を開くと例外(またはそのブロックの他の何か)が発生した場合でも、接続は上部に表示され、他のすべてのハンドレス例外のようになります。

6
BFree

以前とまったく同じように、例外をキャッチ(または無視)できます。重要なのは、データベース接続の破棄について心配する必要がないことです。

つまり、アプリケーションで他の理由(ロギングなど)のために例外をトラップする必要がある場合は、先に進みますが、データベース接続を破棄するだけの場合は、トラップを行う必要はありません。

using (SqlConnection conn = new SqlConnection(...))
{
    // do your db work here
    // whatever happens the connection will be safely disposed
}

他の理由で例外をキャッチしたい場合でも、それを行うことができます。

try
{
    using (SqlConnection conn = new SqlConnection(...))
    {
        // do your db work here
        // whatever happens the connection will be safely disposed
    }
}
catch (Exception ex)
{
    // do your stuff here (eg, logging)
    // nb: the connection will already have been disposed at this point
}
finally
{
    // if you need it
}
4
LukeH