使用标准try/catch包装对类的方法的调用

Ric*_*h S 19 .net c# delegates exception

我有一个有大约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;
}
Run Code Online (Sandbox Code Playgroud)

也许还有更实用的方法吗?

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

此外,如果我执行上述操作,我可以计时方法,并记录方法调用等.它看起来有点笨拙(而不是强类型).

谢谢Rich.

Mar*_*ell 32

你应该能够做以下事情:

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

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


cka*_*ras 12

我认为你的基本想法很好,但有一种更简单的方法来实现它(至少你使用的是.Net 3.5或更新版本):

void WithStandardRetryLogic(Action method) 
{
    try
    {
        method();
    }
    catch (Some.Timeout.Error.Or.Whatever te)     
    {         
        // take some action.. maybe retry etc..      
    } 
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

WithStandardRetryLogic(delegate() { CallUpdatePassenger(PassengerId, PassengerName, PhoneNumber); });
Run Code Online (Sandbox Code Playgroud)

这也可能是AOP框架可能有用的东西,但我还没有尝试过这个解决方案.