我有许多WebService方法都包含一些非常的样板代码,用于将实际工作包装在try / catch / finally中,并在catch / finally中执行相同的任务。因此,作为一种封装所有共享catch / finally内容的方法,我编写了一个简单的泛型。
这有效并且真正消除了一堆重复的代码,但感觉很笨,而且语法非常迟钝。每次我回到这里,我的大脑都会扭曲,试图找出它(一个明显的标志,这不是一个好的设计)。我正在寻找关于这是否是一件疯狂事情的反馈,以及是否有更好的方法来处理它。
这是我的模板:
public delegate T2 RestfulServiceRequest<T1, T2>(T1 req);
static class RestfulService
{
public static T2 ExceptionHandler<T1, T2>(RestfulServiceRequest<T1, T2> serviceCall, T1 req)
{
if (req == null)
throw new BadRequestException(new ArgumentNullException("Invalid or missing request object"));
try
{
return serviceCall(req);
}
catch (RestfulException e)
{
// log it and rethrow
Logger.Write(e);
throw;
}
catch (Exception e)
{
Logger.Error(e);
// wrap in a consistent exception for propagation back to caller
throw new InternalServerException(e);
}
finally
{
Logger.Debug("Complete");
}
}
}
}
以下是它的用法:
public class Initialization : IInitialization
{
// MyMethod thas uses the template
public ApplianceInitResp CreateApplianceServer(ApplianceInitReq req)
{
return RestfulService.ExceptionHandler<ApplianceInitReq, ApplianceInitResp>(delegate(ApplianceInitReq x)
{
// do some work
return new ApplianceInitResp();
}, req);
}
}
}
答案 0 :(得分:2)
我会改变
public static T2 ExceptionHandler<T1, T2>(RestfulServiceRequest<T1, T2> serviceCall, T1 req)
到
public static T2 Invoke<T1, T2>( this T1 req, RestfulServiceRequest<T1, T2> serviceCall)
这会将调用更改为
public class Initialization :IInitialization {
public ApplianceInitResp CreateApplianceServer( ApplianceInitReq req ) {
return req.Invoke( r => {
// do some work
return new ApplianceInitResp();
});
}
}
答案 1 :(得分:1)
使事情更清晰的一件事是定义请求/响应对象实现的接口。然后你就可以摆脱泛型,转而使用接口。请注意,我认为名称更改更能描述您真正想要做的事情。
public interface IServiceResponse { ... }
public class ApplianceInitResp : IServiceResponse { ... }
public interface IServiceRequest { ... }
public class ApplianceInitReq : IServiceRequest { ... }
public delegate IServiceResponse RestfulServiceRequest( IServiceRequest req );
static class RestfulService
{
public static IServiceResponse
Invoke( RestfulServiceRequest serviceCall, IServiceRequest req)
{
if (req == null)
throw new BadRequestException( ...inner-exception... );
try
{
return serviceCall(req);
}
catch (RestfulException e)
{
Logger.Write(e);
throw;
}
catch (Exception e)
{
Logger.Error(e);
throw new InternalServerException(e);
}
finally
{
Logger.Debug("Complete");
}
}
}
public class Initialization : IInitialization
{
// MyMethod thas uses the template
public ApplianceInitResp CreateApplianceServer(ApplianceInitReq req)
{
return RestfulService.Invoke(
delegate(ApplianceInitReq x)
{
// do some work
return new ApplianceInitResp();
},
req );
}
}
答案 2 :(得分:1)
我建议你寻找提供AOP功能的框架(比如Spring.NET,Unity)。这些将帮助您减少CreateApplianceServer()调用仅仅
public ApplianceInitResp CreateApplianceServer(ApplianceInitReq req)
{
// Do some work
return new ApplianceInitResp();
}
通过方面处理入口/出口和异常日志记录。也许,如果你有一些常见的参数,你也可以将参数验证插入方面。
当然,会有学习曲线税,但是,相信我,结果值得。您将大大减少方法中的样板代码量。
答案 3 :(得分:0)
我同意这样做有点笨拙,但是,我并没有立即看到重复工作的“完美”方式,以尽量减少重复。
我唯一想到的是,如果你能以某种方式使用界面或稍微分解一下,我不确定我是怎么做的,但我可以说,对于正在进行的改变我不要我想我会离开这个,至少没有真正好的文档。
答案 4 :(得分:0)
我认为你所做的很好。这种编码在脚本语言中很常见 - 但由于它们是动态类型的,所以它不那么冗长。它在函数式语言中也很常见 - 但它的冗长程度更低,因为它们具有如此好的类型推断!在C#中,你对类型推理系统的当前局限性有所阻碍,但在第4版中会更好。
另一种方法是使用大量的接口或类来封装你的工作。在执行此操作时,您在调用时的类型名称较少,但总体代码更多。