C# 重构异常处理
在我的一个类中,我调用了一个存储库,其中包含一些错误处理。我想重构错误处理代码,因为它是非常重复的,唯一真正改变的是消息 我的代码当前看起来像这样:C# 重构异常处理,c#,exception,refactoring,C#,Exception,Refactoring,在我的一个类中,我调用了一个存储库,其中包含一些错误处理。我想重构错误处理代码,因为它是非常重复的,唯一真正改变的是消息 我的代码当前看起来像这样: public IList<User> GetUser() { try { return _repository.GetUsers(); } catch (WebException ex) { ErrorMessages.Add("..."); _lo
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
}
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;
}
public IList GetUser()
{
尝试
{
返回_repository.GetUsers();
}
捕获(WebException ex)
{
ErrorMessages。添加(“…”);
_logger.ErrorException(“…”,ex);
}
捕获(SoapException-ex)
{
ErrorMessages。添加(“…”);
_logger.ErrorException(“…”,ex);
}
等
}
我可以用调用另一个方法来替换catch块中的那些行,该方法接受错误消息值和记录器消息值。然而,我想我也可以使用Action参数来实现这一点,但我在使用Func和Action方面非常缺乏经验,并且不知道使用其中一个参数比使用一个方法有什么好处
我的问题是重构这段代码的最佳方式是什么,以及为什么一种方式比另一种方式更有利(根据我上面的例子)
感谢您的帮助。假设异常类型始终相同,但消息不同,您可以执行以下操作:
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
的参数
如果混合使用带有和不带返回类型的方法,最好不要使用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());
IList用户;
试试(“我的web消息。”,“我的soap消息。”,()=>users=\u repository.GetUsers());
您可以使用lambdas来帮助实现这一点
如果将通用错误处理程序定义为接受Action
类型的参数,则可以在错误处理程序中调用该操作
您不需要担心返回值,因为您在调用点编写的lambda可以处理这个问题
例如,您的常规处理程序可能如下所示:
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
}
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;
}
然后你可以这样使用它:
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
}
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;
}
public IList GetUser()
{
IList result=null;
AttemptAction(()=>result=_repository.GetUsers());
返回结果;
}
您可以使用面向方面的编程。
将所有重复代码放在称为方面的特殊类中的想法
您的代码将与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);
}
}
[例外日志]
公共IList GetUser()
{
返回_repository.GetUsers();
}
公共类ExceptionLogger:OnMethodBoundaryAspect
{
//获取记录器和错误消息
public override void OnException(MethodExecutionArgs args)
{
ErrorMessages。添加(“…”);
_logger.ErrorException(“…”,ex);
}
}
对于c#,您可以使用PostSharp、Castle.Windsor或Unity框架。请注意,
T的返回类型将使处理无效方法变得有点笨拙。另一个例子是,您不应该仅仅因为可以这样做就这样做。这个问题的答案很好。@gbjbaanb:谢谢!但是为什么不应该这样做?我承认这不是我最喜欢的构造,我可以用它编写很多代码。我也很想知道为什么你不应该这么做。顺便说一下谢谢你的回答为什么?!“在离用户最近的层中,尝试/捕获所有内容都是正常的。”。最终,此结果将返回到视图。感谢您的回答。但是,我认为应该是相反的,因为错误消息对于所有调用都是不同的。有一个GetUsers调用,但也有其他调用,如GetCategories。我应该在我原来的帖子中提到这一点,sorry@Serberuss没关系,这是一种通用方法。如果需要,您可以像MartinMulder的回答一样传递错误消息。