7

我有一种特殊情况,我需要捕获异常并将一个对象返回给客户端以代替异常。我不能将异常处理逻辑放在更高级别,即将 Foo 包装在 try 子句中。

最好用一些示例代码来演示。异常处理逻辑模糊了方法的意图,如果我有许多类似意图的方法,在 Foo 类中,我发现自己重复了大部分的 catch 逻辑。

在下面的代码中包装常见异常功能的最佳技术是什么?

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

根据李的评论更新


一种可能性是使用通用辅助方法。像这样的东西:

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 {
  //...
}

然后在catch中,只需使用,例如:

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方法中使用一个处理程序并通用处理异常。

此外,如果您确实需要在那里进行日志记录,则不需要从 catch 块返回任意对象,只需使用throw;它来让它在堆栈中游荡。

于 2012-08-03T17:57:51.230 回答