7

例外をトラップし、例外の代わりにオブジェクトをクライアントに返す必要がある特定の状況があります。例外処理ロジックをより高いレベルに置くことはできません。つまり、Fooをtry句内にラップします

いくつかのサンプルコードでデモンストレーションするのが最善です。例外処理ロジックはメソッドの意図を曇らせており、Fooクラスに同様の意図のメソッドが多数ある場合は、キャッチロジックのほとんどを繰り返していることに気付きます。

以下のコードで一般的な例外機能をラップするための最良の手法は何でしょうか?

public class Foo
{
     public Bar SomeMethodThatCanThrowExcepetion()
     {
          try
          {
              return new Bar().Execute();
          }
          catch(BazException ex)
          {
              WriteLogMessage(ex, Bar.ErrorCode);
              return new Bar() { ErrorMessage = ex.Message, ErrorCode = Bar.ErrorCode;}                  
          }
     }

     public Baz SomeMethodThatCanThrowExcepetion(SomeObject stuff)
     {
          try
          {
              return new Baz(stuff).Execute();
          }
          catch(BazException ex)
          {
              WriteLogMessage(ex, Baz.ErrorCode);
              return new Baz() { ErrorMessage = ex.Message, ErrorCode = Baz.ErrorCode;}                  
          }
     }
 } 
4

4 に答える 4

5

リーのコメントごとに更新


1つの可能性は、一般的なヘルパーメソッドを使用することです。このようなもの:

T TryExecute<T>(Func<T> action, int ErrorCode)
{
    try
    {
        return action();
    }
    catch (Exception ex)
    {
        result = Activator.CreateInstance<T>();
        typeof(T).GetProperty("ErrorMessage").SetValue(result, ex.Message, null);
        typeof(T).GetProperty("ErrorCode").SetValue(result, ErrorCode, null);
        return result;
    }
    return result;
}

BarBazを変更できる場合は、 Tに要件を設定することでこれを改善できます。

public interface IError
{
    public string ErrorMessage { get; set; }
    public int ErrorCode { get; set; }
}

T TryExecute<T>(Func<T> action, int ErrorCode) where T : IError
{
    try
    {
        return action();
    }
    catch (Exception ex)
    {
        result = Activator.CreateInstance<T>();
        result.ErrorMessage = ex.Message;
        result.ErrorCode = ErrorCode;
        return result;
    }
}

次に、以下を使用します。

return TryExecute<Bar>(new Bar().Execute, Bar.ErrorCode);

と:

return TryExecute<Baz>(new Baz(stuff).Execute, Baz.ErrorCode);

それはあなたの特定のデザインにとって過度の抽象化であるかもしれないし、そうでないかもしれません。悪魔は細部に宿っています。

于 2012-08-03T18:05:23.550 に答える
5

基本クラスはどうですか:

public class ErrorCapable {
  public string ErrorMessage { set; get; }
  public int ErrorCode { set; get; }

  public static ErrorCapable<T> Oops(Exception exc) where T : ErrorCapable, new() {
    // Code for logging error here
    return new T() { ErrorMessage = exc.Message, ErrorCode = exc.ErrorCode };
  }
}

public class Bar : ErrorCapable {
  //...
}
public class Baz : ErrorCapable {
  //...
}

次に、キャッチで、たとえば次を使用します。

return ErrorCapable.Oops<Bar>(ex);
于 2012-08-03T18:05:26.530 に答える
2

私はあなたができる最善のことは次のようなものだと思います:

public T TryOrDefault<T>(Func<T> act, int errorCode, Func<BazException, T> onError)
{
    try
    {
        return act;
    }
    catch(BazException ex)
    {
        WriteLogMessage(ex, errorCode);
        return onError(ex);
    }
}

次に、それに関して他のメソッドを書くことができます:

public Bar SomeMethodThatCanThrowException()
{
    Bar b = new Bar();
    return ExecOrDefault(() => b.Execute(), Bar.ErrorCode, ex => new Bar { ErrorMessage = ex.Message, ErrorCode = Bar.ErrorCode });
}
于 2012-08-03T18:07:28.143 に答える
2

すべてのメソッドで明示的なロギングが本当に必要ですか?すべてのメソッドに例外ロジックを含める代わりにMain、プログラムのメソッドに1つのハンドラーを設定し、例外を一般的に処理します。

また、catchブロックから任意のオブジェクトを返す必要はありません。実際にそこにログを記録する必要がある場合は、単にthrow;スタックを移動させるために使用します。

于 2012-08-03T17:57:51.230 に答える