有问题的代码是由机器人(CodeSmith)编写的,维护起来很痛苦。它看起来有点类似于:
public AddressProgramTemplate GetById(System.Int32 _id) {
try {
return Service.GetById(_id);
} catch (FaultException<ErrorInfo> ex) {
throw new ProxyServerBusinessException(ex.Detail);
} catch (FaultException) {
throw new ProxyServerBusinessException(null);
} catch (EndpointNotFoundException ex) {
throw new ProxyServerTechnicalException<EndpointNotFoundException>(ex);
} catch (CommunicationObjectFaultedException ex) {
throw new ProxyServerTechnicalException<CommunicationObjectFaultedException>(ex);
} catch (CommunicationException ex) {
throw new ProxyServerTechnicalException<CommunicationException>(ex);
} catch (ObjectDisposedException ex) {
throw new ProxyServerTechnicalException<ObjectDisposedException>(ex);
} catch (TimeoutException ex) {
throw new ProxyServerTechnicalException<TimeoutException>(ex);
}
}
正如您所猜测的那样,它是一个客户端WCF代理代码,所有这些行都会针对每种服务方法重复(并且有很多)。什么对机器人有好处是对我的悲伤,所以我开始重构它。首先,将异常逻辑和处理委托给Microsoft Enterprise Library,并将公共代码迁移到基类:
public TResult WrapServiceMethod<TResult>(Func<TResult> serviceMethod) {
TResult result = default(TResult);
try {
result = serviceMethod();
} catch (Exception ex) {
bool rethrow = ExceptionManager.HandleException(ex, ExceptionPolicyNames.ClientRequestPolicy);
if (rethrow) throw;
}
return result;
}
到目前为止,这个丑陋的尝试/捕获堆变成了一个整洁的单线:
return WrapServiceMethod<AddressProgramTemplate>(() => Service.GetById(_id));
还包括一些努力和无效方法。服务调用使用out
参数时会出现问题:
public void GetPeriod(AddressProgram program, out DateTime startDate, out DateTime endDate){
WrapServiceMethod(() => Service.GetPeriod(program, out startDate, out endDate));
}
结果“无法在匿名方法,lambda表达式或查询表达式中使用ref或out参数'endDate'”,我理解why。
我理想的是能够定义自定义运算符块,例如while()或using(),所以我可以写
wrapexception { ... }
从此过上幸福的生活,但我不认为这个技巧可以用于.NET。假设重写所有没有out
参数的服务方法是最后的选择,我还有其他选择吗?
答案 0 :(得分:2)
听起来像是在使用面向方面的编程库,例如PostSharp。
您可以根据您指定的规则创建在编译后插入IL的异常处理程序,这些规则可以执行诸如捕获异常,记录,跟踪等操作。
这样做的好处是您可以编写一次方面,并将其应用于多种方法。这些方法不会被与手头特定任务无关的代码混乱,因为异常处理等交叉问题由方面处理。
查看http://www.sharpcrafters.com/solutions/monitoring#exception-monitoring上的示例,其中显示了如何处理异常。
答案 1 :(得分:1)
替换out
签名(因此必须更改所有调用代码,我确定您要避免),您可以执行以下操作:
public void GetPeriod(AddressProgram program, out DateTime startDate, out DateTime endDate)
{
var outs = WrapServiceMethod(() =>
{
DateTime sd;
DateTime ed;
Service.GetPeriod(program, out sd, out ed));
return new {sd, ed};
}
startDate = outs.sd;
endDate = outs.ed;
}