我有一种特殊情况,我需要捕获异常并将对象返回给客户端而不是异常。我不能将异常处理逻辑放在更高的级别,即在try子句中包装Foo。
最好用一些示例代码进行演示。异常处理逻辑掩盖了方法的意图,如果我有很多类似意图的方法,在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;}
}
}
}
答案 0 :(得分:5)
根据Lee的评论更新
一种可能性是使用通用辅助方法。像这样:
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;
}
如果您可以修改 Bar 和 Baz ,那么您可以通过在 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);
对于您的特定设计,这可能是也可能不是过度抽象;魔鬼在细节中。
答案 1 :(得分: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);
答案 2 :(得分:2)
您是否真的需要在每种方法中进行显式记录?不是在每个方法中都有异常逻辑,而是在程序的Main
方法中使用一个处理程序并一般地处理异常。
此外,如果您真的需要在那里进行日志记录,则不需要从catch块返回任意对象,只需使用throw;
让它在堆栈中向上移动。
答案 3 :(得分: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 });
}