3

コード内の一部の using ステートメントを削除して、特定の例外をキャッチし、リソースの破棄を手動で処理できるようにすることにしました。新しい try/catch ブロックを実装した後、手元のタスクに対して正しく配置されているかどうか疑問に思っています。

例:

public static DataTable Select(string table, string[] column, Object operand)
{
        DataTable dTable = null;
        SQLiteConnection connection = null;
        SQLiteCommand command = null;
        SQLiteDataReader dReader = null;

        //convert to array for arguments
        StringBuilder query = new StringBuilder();
        query.Append("select ");

        for (int i = 0; i < column.Length; i++)
        {
            query.Append(column[i]);

            if (i < column.Length - 1)
            {
                query.Append(",");
            }
        }
        query.Append(" from ");
        query.Append(table);

        try
        {
            connection = new SQLiteConnection(_connectionString);
            command = new SQLiteCommand(query.ToString(), connection);
            dTable = new DataTable();

            connection.Open();

            dReader = command.ExecuteReader();

            dTable.Load(dReader);

            return dTable;
        }
        catch (SQLiteException sqle)
        {
            //Handle exception
        }
        finally
        {
            connection.Dispose();
            command.Dispose();
            dReader.Dispose();
            dTable.Dispose();
        }
        return null;
}

この例では、SQL 操作自体に try/catch のみを実装しました。スローされた例外を確実に認識し、リソースが正しく破棄されるようにするためです。その後、提供されたインデクサーは保護され、GUI を介して作成されますが、これにより for ループが例外に対して開かれたままになっていることに気付きました。

メソッド全体を try/catch ステートメントにカプセル化するのが賢明でしょうか、それとも過度に用心深いのでしょうか? ステートメント自体の配置を管理する際のベスト プラクティスを探していると言えます。

御時間ありがとうございます!

編集:

using ステートメントは、リソースの破棄と管理を処理するという点で理想的であることはわかっていますが、質問の冒頭で述べたように、特定の種類の例外、特に SQLite コンポーネントから生成された例外をキャッチできるようにしたいと考えています。

4

6 に答える 6

9

チェックを忘れないでnullください:

finally {
  if (connection != null) connection.Dispose();
  if (command != null) command.Dispose();
  if (dReader != null) dReader.Dispose();
  if (dTable != null) dTable.Dispose();
}

コンストラクターの 1 つが例外をスローする可能性があります。その場合、オブジェクトは初期化されていません。

于 2011-04-03T20:28:50.793 に答える
3

リソース管理に関心があるのに、try/catch を明示的に使用するのはなぜですか? using代わりに使用してください:

using(SQLiteConnection connection = new SQLiteConnection(_connectionString))
{ 
   ..
   using(SQLiteCommand command = new SQLiteCommand(query.ToString(), connection))
   {
      using(SQLiteDataReader  reader = dReader = command.ExecuteReader())
      {
          dTable.Load(dReader);
      }
   }
}

また、現在 を返してdTableいますが、最終ブロックで破棄しています。

于 2011-04-03T20:33:51.137 に答える
2

データベースの問題の範囲外で例外がスローされる可能性があると思われる場合は、メソッド全体を try/catch で囲むことができます。キャッチしたものによって例外を簡単に区別できます。例えば:

DataTable dTable = null;
SQLiteConnection connection = null;
SQLiteCommand command = null;
SQLiteDataReader dReader = null;

try
{
  // non-DB code

  // DB code
}
catch (SQLiteException sqle)
{
  // Handle DB exception
}
catch (IndexOutOfRangeException ie)
{
  // If you think there might be a problem with index range in the loop, for example
}
catch (Exception ex)
{
  // If you want to catch any exception that the previous catches don't catch (that is, if you want to handle other exceptions, rather than let them bubble up to the method caller)
}
finally
{
  // I recommend doing some null-checking here, otherwise you risk a NullReferenceException.  There's nothing quite like throwing an exception from within a finally block for fun debugging.
  connection.Dispose();
  command.Dispose();
  dReader.Dispose();
  dTable.Dispose();
}
return null;
于 2011-04-03T20:31:43.197 に答える
1

このリファクタリングで導入したより大きな問題は、中間エンティティの 1 つの作成が失敗したときに何が起こるかを考えるとわかります。たとえば、接続の作成でスローされた場合、それらすべての null 変数に対して Dispose を呼び出そうとする finally ブロックでスローされた例外はどうなるでしょうか? 少なくとも事前に null をチェックするか、finally 内に追加の try/catch を入れてください。すでにこれらの問題を指摘している Resharper を使用することでメリットが得られると思います。

于 2011-04-03T20:32:11.217 に答える
1

それがベスト プラクティスかどうかはわかりませんが、通常、データベース アクセス、ファイル I/O などの外部リソースにアクセスするコード ブロックの周りに try/catch ステートメントを配置します。さまざまな理由で例外が発生する可能性があります (アクセスできないリソース) 、I/O エラーなど)。私は自分が管理しているコードを保護しません - そこで単体テストの出番です

ところで: ループを ? に置き換えることができることをご存知string.Join()ですか?

更新: 明確にするために: try/catch ブロックは、特定の例外をキャッチしてカスタム ロジックを実行する場合にのみ意味があります。それ以外の場合はusing、適切な場所で例外をバブルアップさせて対処する必要があります (たとえば、サーバーが利用できないなどの理由で一部のデータを保存できなかったことをユーザーに通知します)。

于 2011-04-03T20:32:38.317 に答える
0

あなたが心配しているのは、物事を適切に処分することだけである場合、これには「using」ブロックを使用する必要があります。 http://msdn.microsoft.com/en-us/library/yh598w02.aspx

于 2011-04-03T20:34:26.147 に答える