用标准的try/catch封装对类上方法的调用



我有一个类,它有大约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;
}

也许有更实际的方法?

代码是自动生成的(由我编写的工具),我可以很容易地包含上面的东西,但我想避免为每个方法调用编写上面的代码。

同样,如果我像上面那样做,我可以计时方法,记录方法调用等。它只是看起来有点笨拙(而且不是强类型的)。

谢谢富有。

您应该能够像这样做:

T Execute<T>(Func<T> func) {
    try {
        return func();
    } catch (...) {
        ...
    }
}
bool CallUpdatePassenger(some args here) {
    return Execute( () => realObj.RemoteUpdatePassenger(some args here));
}

或者,您可以使用元编程为底层方法动态编写一个"装饰器"…但除非你熟悉ILGenerator等,否则最好不要这样做-这是一个相当高级的主题。

我认为你的基本想法很好,但是有一种更简单的方法来实现它(至少你们使用的是。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框架可能有用的地方,但我还没有尝试过那个解决方案。

如果你可以使用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();
}

我认为其中一个可能的解决方案是AOP编程。您可以用属性标记任何方法,并在编译时注入try/catch代码。

查看这里的示例

最新更新