3

コード内でロギングを行う必要があります。いくつかの情報を記録するには、社内で開発したライブラリを使用する必要があります。仕組みは次のとおりです。

Recorder recorder = Recorder.StartTiming();
DoSomeWork();
recorder.Stop();  // Writes some diagnostic information.

Stop()が常に呼び出されるようにするために、クリーンな「using」ブロックを許可するラッパークラスを作成しました。

using (RecorderWrapper recorderWrapper = new RecorderWrapper)  // Automatically calls Recorder.StartTiming() under the covers
{
   DoSomeWork();
}  // When the recorderWrapper goes out of scope, the 'using' statement calls recorderWrapper.Dispose() automatically - which calls recorder.Stop() under the covers

これまでのところうまく機能しています。ただし、私の会社が要求している変更があります。これは、元のコードでは次のようになります。

Recorder recorder = Recorder.StartTiming();
try
{
   DoSomeWork();
}
catch (Exception ex)
{
   recorder.ReportFailure(ex);  // Write out some exception details associated with this "transaction"
}
recorder.Stop();  // Writes some diagnostic information.

RecorderWrapperで「使用する」スコープブロックすべてでtry/catchを回避したいと思います。「ReportFailure()」呼び出しに対応し、「using」スコープブロックを活用する方法はありますか?

具体的には、チームの全員が「成功の落とし穴に陥る」、つまり正しいことを簡単に行えるようにしてほしいと思っています。私にとって、これは、recorder.Stop()を呼び出すことを忘れたり、try/catchを忘れたりすることを本当に難しくすることを意味します。

ありがとう!

4

8 に答える 8

7

これを非表示にするメソッドをレコーダーで作成できる場合があります。

public void Record(Action act)
{
    try
    {
        this.StartTiming();
        act();
    }
    catch(Exception ex)
    {
        this.ReportFailure(ex);
    }
    finally
    {
        this.Stop();
    }
}

したがって、あなたの例は次のようになります。

recorder.Record(DoSomeWork);
于 2009-11-16T19:31:47.003 に答える
3

あなたはいつでも次のようなことを試すことができます:

280Z28 による編集:StartNew()ここでは に似た静的メソッドを使用していますStopwatch.StartNew()Recorderクラスを作成し、からIDisposable呼び出します。これ以上明確になることはないと思います。Stop()Dispose()

using (Recorder recorder = Recorder.StartNew())
{
    try
    {
        DoSomeWork();
    }
    catch (Exception ex)
    {
        recorder.ReportFailure(ex);
    }
}
于 2009-11-16T19:32:30.540 に答える
3

持っている RecorderWrapper を引き続き使用できますが、実行したいことのラムダを受け入れる TryExecuting メソッドを追加して、それを try/catch ブロックで実行します。例えば:

using (RecorderWrapper recorderWrapper = new RecorderWrapper)  // Automatically calls Recorder.StartTiming() under the covers
{
    recorderWrapper.TryExecuting(() => DoSomeWork());
}

RecorderWrapper の内部:

public void TryExecuting(Action work)
{
    try { work(); }
    catch(Exception ex) { this.ReportFailure(ex); }
}
于 2009-11-16T19:38:57.863 に答える
1

で使用されるパターンをコピーし、アクティブに完了TransactionScopeする必要があるラッパーを作成できます。 を呼び出さない場合、メソッド (いずれかの方法で呼び出されます) は例外を想定し、処理コードを実行します。Complete()Dispose()

using(Recorder recorder = Recorder.StartTiming()) {
    DoSomeWork();
    recorder.Complete();
}

ただし、個人的には、try/catch に固執します (将来のメンテナーにとってはより明確になります) Exception

于 2009-11-16T19:27:36.917 に答える
1

いいえ、using ブロックは、try/finally ブロックのシンタックス シュガーにすぎません。try/catch には対応していません。その時点で、ログ記録のために例外が必要なように見えるため、自分で処理する必要があります。

于 2009-11-16T19:29:09.237 に答える
1

using ブロックは事実上、問題のオブジェクトに対して dispose を呼び出す try/finally ブロックです。

したがって、この:

using(a = new A())
{
    a.Act();
}

は(私が思うに、正確に)これと同等です:

a = new A();
try
{
    a.Act();
}
finally
{
    a.Dispose();
}

そして、キャッチを try ブロックの最後に追加できます。

編集:

ロブのソリューションの代替として:

Recorder recorder = Recorder.StartNew()
try
{
    DoSomeWork();
}
catch (Exception ex)
{
    recorder.ReportFailure(ex);
}
finally
{
    recorder.Dispose();
}
于 2009-11-16T19:29:43.807 に答える
1

おっと、StartTiming によって Recorder の新しいインスタンスが作成されていることに気づきませんでした。これを考慮してコードを更新しました。Wrap 関数は Recorder パラメーターを使用しなくなりましたが、代わりに作成したレコーダーを引数として呼び出し元から渡されたアクション デリゲートに渡し、呼び出し元が必要に応じてそれを利用できるようにします。

うーん、私はこのパターンに非常に似た何かをする必要がありました.lambdas、Actionデリゲート、クロージャーはそれを簡単にします:

まず、ラッピングを行うクラスを定義します。

public static class RecorderScope
{
   public static void Wrap(Action<Recorder> action)
   {
      Recorder recorder = Recorder.StartTiming();
      try
      {
         action(recorder);
      }
      catch(Exception exception)
      {
         recorder.ReportFailure(exception);
      }
      finally
      {
         recorder.Stop();
      }
   }
}

今、次のように使用します:

RecorderScope.Wrap(
   (recorder) =>
   {
      // note, the recorder is passed in here so you can use it if needed -
      // if you never need it you can remove it from the Wrap function.
      DoSomeWork();
   });

ただし、1 つ質問があります。キャッチ ハンドラが例外を再スローせずに飲み込むことが本当に望ましいのでしょうか。これは通常、悪い習慣です。

ところで、このパターンに便利な機能を追加します。ただし、このインスタンスで行っていることには当てはまらないように聞こえます: 上記のようなことをしたいと思ったことはありますが、一連の起動アクションと完了アクションでコードをラップする必要がありますが、特定の例外処理コードをコーディングできます。Wrap 関数を変更して Action デリゲートも取り、T を Exception に制約すると、ユーザーがキャッチする例外の種類を指定できるラッパーと、それを処理するために実行するコードが得られます。たとえば、次のようになります。

public static class RecorderScope
{
   public static void Wrap(Action<Recorder> action, 
      Action<Recorder, T1> exHandler1)
      where T1: Exception
   {
      Recorder recorder = Recorder.StartTiming();
      try
      {
         action(recorder);
      }
      catch(T1 ex1)
      {
         exHandler1(recorder, ex1);
      }
      finally
      {
         recorder.Stop();
      }
   }
}

使用するには..(例外のタイプを指定する必要があることに注意してください。明らかに推測できないためです。これが必要です):

RecorderScope.Wrap(
   (recorder) =>
   {
      DoSomeWork();
   },
   (recorder, MyException ex) =>
   {
      recorder.ReportFailure(exception);
   });

次に、複数の例外ハンドラー デリゲートを受け取る Wrap 関数の複数のオーバーロードを提供することで、このパターンを拡張できます。通常は 5 つのオーバーロードで十分です。一度に 5 つ以上の異なる種類の例外をキャッチする必要があることは非常にまれです。

于 2009-11-16T20:05:58.603 に答える
0

別のレベルの間接性を追加しないでください。例外をキャッチする必要がある場合は、ブロックを使用try..catch..finallyして呼び出します。Dispose()finally

于 2009-11-16T19:30:39.967 に答える