关于在C#中创建可重用的try/catch块的建议?

关于在C#中创建可重用的try/catch块的建议?,c#,.net,exception-handling,try-catch,C#,.net,Exception Handling,Try Catch,我有一个类,其中有大约20个方法。每一个都进行一些web服务消息处理。我只需要对其进行更改,并意识到这些方法中的每一种都有完全相同的try/catch: try { /* *** actual processing specific to each method goes here *** */ } catch (FaultException<CustomException> cfex)

我有一个类,其中有大约20个方法。每一个都进行一些web服务消息处理。我只需要对其进行更改,并意识到这些方法中的每一种都有完全相同的try/catch:

        try
        {
            /* *** actual processing specific to each method goes here *** */
        }
        catch (FaultException<CustomException> cfex)
        {
            // common stuff
        }
        catch (CustomException cfex)
        {
            // common stuff
        }
        catch (Exception ex)
        {
            // common stuff
        }
        finally
        {
            FinalizeServiceCall(wsBus, wsMessage, response, logProps);
        }
试试看
{
/****每种方法的实际处理如下****/
}
捕获(故障异常cfex)
{
//普通的东西
}
捕获(自定义异常cfex)
{
//普通的东西
}
捕获(例外情况除外)
{
//普通的东西
}
最后
{
FinalizeServiceCall(wsBus、wsMessage、response、logProps);
}

我的问题是,;有没有办法让每个方法都有完全相同的try/catch块?我的想法是.NET有类似于
TransactionScope
的东西,它可以在离开该块时检测是否发生异常。有没有我可以利用这样的东西来制作一个普通的try/catch块?还有其他想法吗?

如果参数相同或接近相同,则始终可以传入代理。如果不是,您可以通过反射调用代码,并将参数“object[]”传递给invoke

我会这样做:

创建一个包含try/catch的方法,并向其中传递一个
操作
,然后在try部分中执行该操作:

public void Method1()
{
    Action action = () =>
    {
        // actual processing of Method 1
    };
    SafeExecutor(action);
}

public void Method1b()
{
    SafeExecutor(() =>
    {
        // actual processing of Method 1
    });
}

public void Method2(int someParameter)
{
    Action action = () =>
    {
        // actual processing of Method 2 with supplied parameter
        if(someParameter == 1)
        ...
    };
    SafeExecutor(action);
}

public int Method3(int someParameter)
{
    Func<int> action = () =>
    {
        // actual processing of Method 3 with supplied parameter
        if(someParameter == 1)
            return 10;
        return 0;
    };
    return SafeExecutor(action);
}

private void SafeExecutor(Action action)
{
    SafeExecutor(() => { action(); return 0; });
}

private T SafeExecutor<T>(Func<T> action)
{
    try
    {
        return action();
    }
    catch (FaultException<CustomException> cfex)
    {
        // common stuff
    }
    catch (CustomException cfex)
    {
        // common stuff
    }
    catch (Exception ex)
    {
        // common stuff
    }
    finally
    {
        FinalizeServiceCall(wsBus, wsMessage, response, logProps);
    }

    return default(T);
}
公共作废方法1()
{
动作动作=()=>
{
//方法1的实际处理
};
安全执行人(行动);
}
公开无效方法1b()
{
安全执行器(()=>
{
//方法1的实际处理
});
}
公共void方法2(int-someParameter)
{
动作动作=()=>
{
//使用提供的参数实际处理方法2
if(someParameter==1)
...
};
安全执行人(行动);
}
公共int方法3(int-someParameter)
{
Func action=()=>
{
//使用提供的参数实际处理方法3
if(someParameter==1)
返回10;
返回0;
};
返回安全执行人(行动);
}
私人无效安全执行人(行动)
{
安全执行器(()=>{action();返回0;});
}
私人安全执行人(职能行动)
{
尝试
{
返回动作();
}
捕获(故障异常cfex)
{
//普通的东西
}
捕获(自定义异常cfex)
{
//普通的东西
}
捕获(例外情况除外)
{
//普通的东西
}
最后
{
FinalizeServiceCall(wsBus、wsMessage、response、logProps);
}
返回默认值(T);
}
SafeExecutor
的两个版本使您可以处理有返回类型和无返回类型的方法。

Method1b
表明在方法中不需要变量
action
,如果您认为它更可读,您可以将其内联。

有一些方法可以让您轻松做到这一点-首先,对于我来说,我已经开始使用AOP来捕获我的异常

这将有效地改变您的代码

try
        {
            /* *** actual processing specific to each method goes here *** */
        }
        catch (FaultException<CustomException> cfex)
        {
            // common stuff
        }
        catch (CustomException cfex)
        {
            // common stuff
        }
        catch (Exception ex)
        {
            // common stuff
        }
        finally
        {
            FinalizeServiceCall(wsBus, wsMessage, response, logProps);
        }
试试看
{
/****每种方法的实际处理如下****/
}
捕获(故障异常cfex)
{
//普通的东西
}
捕获(自定义异常cfex)
{
//普通的东西
}
捕获(例外情况除外)
{
//普通的东西
}
最后
{
FinalizeServiceCall(wsBus、wsMessage、response、logProps);
}
变成

[HandleException( Exception , FaultException<CustomException>, 
                      "Error Getting Details" )]
    public MYType GetDetails( string parameter )
    {
        //.... call to service
    }
[HandleException(异常、故障异常、,
“获取详细信息时出错”)]
公共MYType GetDetails(字符串参数)
{
//…呼叫服务
}
使用Postsharp-


或者有一篇关于的博文-我还没有尝试过这篇博文,但是你可以在一个方法中编写上面的代码,该方法将一个动作或Func作为一个参数,该参数决定了在抛出块中应该调用的方法及其参数

因此,如果在抛出块中调用
M(1,“string”)
,它将变成
DoStuff(M,1,“string”)

多斯塔夫看起来像

void DoStuff<T1, T2, TResult>(Func<T1, T2, TResult> myMethod, T1 arg1, T2 arg2)
{
        try
        {
            myMethod(arg1, arg2)
        }
        catch (FaultException<CustomException> cfex)
        {
            // common stuff
        }
        catch (CustomException cfex)
        {
            // common stuff
        }
        catch (Exception ex)
        {
            // common stuff
        }
        finally
        {
            FinalizeServiceCall(wsBus, wsMessage, response, logProps);
        }
}
void DoStuff(Func myMethod,T1 arg1,T2 arg2)
{
尝试
{
myMethod(arg1、arg2)
}
捕获(故障异常cfex)
{
//普通的东西
}
捕获(自定义异常cfex)
{
//普通的东西
}
捕获(例外情况除外)
{
//普通的东西
}
最后
{
FinalizeServiceCall(wsBus、wsMessage、response、logProps);
}
}
您已经确定了一个交叉问题。您可以使用面向方面编程(AOP)方法来解决这个问题。这可以在运行时通过使用位于类前面的代理来执行,也可以在编译期间通过使用修改编译代码的AOP工具来执行


在过去,我已经利用了来做这件事(在运行时)。或者,如果调用了
Complete()
,您可以使用其他AOP框架之一,例如。

TransactionScope
在其
Dispose()
方法中可能看起来像是(我猜
Complete()
将标志设置为
true
,并且
Dipose()
如果是
true,则提交,否则则回滚)。为什么不将try/catch逻辑提升一个级别呢?@Cody-我想将其提升一个级别,但这些方法都是WCF[OperationContract]服务方法,因此实际上没有更高的级别,除非我创建一个。@Etienne-你是对的,它检查Dispose中的完整方法。我知道这一点,但当我问这个问题时,我完全忘记了:)为什么您的WCF实现会捕获错误异常?这正是我创建的。G