重构异常处理
本文关键字:异常处理 重构 | 更新日期: 2023-09-27 18:14:40
在我的一个类中,我有一个对存储库的调用,它有一些错误处理。我想重构错误处理代码,因为它是相当重复的,唯一真正改变的是消息。
我的代码现在看起来像这样:
public IList<User> GetUser()
{
try
{
return _repository.GetUsers();
}
catch (WebException ex)
{
ErrorMessages.Add("...");
_logger.ErrorException("...", ex);
}
catch (SoapException ex)
{
ErrorMessages.Add("...");
_logger.ErrorException("...", ex);
}
... etc
}
我可以将catch块中的这些行替换为对另一个方法的调用,该方法接受错误消息值和记录器消息值。然而,我想我也可以使用Action<>参数来做到这一点,但我在使用Func<>和Action<>方面非常缺乏经验,并且没有真正看到使用它们中的一个比方法有什么好处。
我的问题是重构这段代码的最佳方式是什么,为什么一种方式比另一种方式更有利(就像我上面的例子一样)。
谢谢你的帮助
你可以使用lambdas来帮助你。
如果你定义了通用错误处理程序来接受类型为Action
的参数,那么你可以在错误处理程序中调用该操作。
您不需要担心返回值,因为在调用时编写的lambda可以处理这个问题。
例如,您的通用处理程序可能像这样:
public void AttemptAction(Action action)
{
try
{
action();
}
catch (WebException ex)
{
ErrorMessages.Add("...");
_logger.ErrorException("...", ex);
// Rethrow?
}
catch (SoapException ex)
{
ErrorMessages.Add("...");
_logger.ErrorException("...", ex);
// Rethrow?
}
}
然后你可以这样使用:
public IList<User> GetUser()
{
IList<User> result = null;
AttemptAction(() => result = _repository.GetUsers());
return result;
}
假设异常类型总是相同的,但消息不同,您可以这样做:
static public T Try<T>(string webMessage, string soapMessage, Func<T> func)
{
try
{
return func();
}
catch (WebException ex)
{
ErrorMessages.Add(webMessage);
_logger.ErrorException(webMessage, ex);
}
catch (SoapException ex)
{
ErrorMessages.Add(soapMessage);
_logger.ErrorException(soapMessage, ex);
}
}
这个Try-method将使用Func<T>
类型的委托来调用函数并返回其值。函数将位于同一个try-catch块中。消息是通过参数提供的。现在,在代码的其他地方,你可以这样调用它:
var users = Try("My web message.", "My soap message.", () => _repository.GetUsers());
或者,在您的情况下更短(当不使用参数时):
var users = Try("My web message.", "My soap message.", _repository.GetUsers);
当然,您可以根据自己的喜好修改和安排Try
的参数。
如果您混合了有返回类型和没有返回类型的方法,最好不要使用Func
,而是使用Action
。这将能够符合所有情况:
static public void Try(string webMessage, string soapMessage, Action action)
{
try
{
action();
}
catch (WebException ex)
{
ErrorMessages.Add(webMessage);
_logger.ErrorException(webMessage, ex);
}
catch (SoapException ex)
{
ErrorMessages.Add(soapMessage);
_logger.ErrorException(soapMessage, ex);
}
}
但是这个解决方案使代码更难阅读/维护:
IList<User> users;
Try("My web message.", "My soap message.", () => users = _repository.GetUsers());
您可以使用面向方面的编程http://en.wikipedia.org/wiki/Aspect-oriented_programming。将所有重复的代码放在称为aspect的特殊类中。
你的代码看起来像PostSharp
[ExceptionLogger]
public IList<User> GetUser()
{
return _repository.GetUsers();
}
public class ExceptionLogger: OnMethodBoundaryAspect
{
//getting _logger and ErrorMessages
public override void OnException(MethodExecutionArgs args)
{
ErrorMessages.Add("...");
_logger.ErrorException("...", ex);
}
}
对于c#,你可以使用PostSharp, Castle。