我有一个包含大约200多种方法的类,每种方法都会调用数据库或网络资源。
理想情况下,我想将每个调用包装在try / catch中,以捕获任何常见的网络或SQL异常,并让用户有机会再次尝试(如果适用)。但是,将此代码添加到每个调用中将非常耗时,并且就代码而言也会膨胀。
我已经考虑过在另一个方法中包装每个方法调用,创建一个委托,并将委托代码包装在try / catch中......就像这样......
(忽略语法......这只是一个概念性示例)
bool CallUpdatePassenger(int PassengerId,string PassengerName,string PhoneNumber)
{
Delegate del= Delegate.CreateDelegate(typeof(UpdatePassengerDelegate), typeof(IPassengerServices).GetMethod("RemoteUpdatePassenger"));
bool Res=(bool)CallDelegate(del,PassengerName,PhoneNumber);
}
object CallDelegate(Delegate del,params object[] args)
{
object Result=null;
try
{
Result=del.DynamicInvoke(args);
}
catch (Some.Timeout.Error.Or.Whatever te)
{
// take some action.. maybe retry etc..
}
return Result;
}
也许还有一种更实用的方法呢?
代码是自动生成的(通过我编写的工具)我可以很容易地包含类似上面的内容,但我想避免为每个方法调用编写上面的代码。
另外,如果我执行上述操作,我可以计算方法,记录方法调用等。它看起来有点笨拙(并且没有强类型)。
由于 丰富。
答案 0 :(得分:29)
你应该能够做类似的事情:
T Execute<T>(Func<T> func) {
try {
return func();
} catch (...) {
...
}
}
bool CallUpdatePassenger(some args here) {
return Execute( () => realObj.RemoteUpdatePassenger(some args here));
}
或者,您可以使用元编程为动态基础方法编写动态“装饰器”...但除非您熟悉ILGenerator
等可能最好不要 - 它是相当先进的主题。
答案 1 :(得分:12)
我认为你的基本想法很好,但有一种更简单的方法来实现它(至少你使用.Net 3.5或更新版本):
void WithStandardRetryLogic(Action method)
{
try
{
method();
}
catch (Some.Timeout.Error.Or.Whatever te)
{
// take some action.. maybe retry etc..
}
}
使用示例:
WithStandardRetryLogic(delegate() { CallUpdatePassenger(PassengerId, PassengerName, PhoneNumber); });
这也可能是AOP框架可能有用的东西,但我还没有尝试过这个解决方案。
答案 2 :(得分:2)
如果您可以使用PostSharp,则可以使用此方面:
[Serializable]
public class RetryAttribute : MethodInterceptionAspect
{
private readonly int _times;
public RetryAttribute(int times)
{
_times = times;
}
public override void OnInvoke(MethodInterceptionArgs args)
{
for (var left = _times; left > 0; left--)
{
try
{
args.Proceed();
break;
}
catch (Exception)
{
}
}
args.Proceed(); // optional
}
}
用法如下:
[Retry(2)]
public static void DoIt()
{
Console.WriteLine("tried");
throw new Exception();
}
答案 3 :(得分:0)