简体   繁体   English

在C#中制作可重用的try / catch块的建议?

[英]Suggestions for making a reusable try/catch block in C#?

I have a class that has about 20-some methods in it. 我有一个类,其中有大约20个方法。 Each one does some web service message processing. 每个人都做一些Web服务消息处理。 I just had to make a change to it, and realized that every one of these methods has the exact same try/catch around it: 我只需对其进行更改,并意识到这些方法中的每一个都具有完全相同的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);
        }

My question is; 我的问题是; instead of having this exact same try/catch block in every method, is there a way to make it common? 而不是在每个方法中都有这个完全相同的try / catch块,有没有办法让它变得常见? My thoughts were that .NET has stuff like TransactionScope that somehow detects if an exception occurs when leaving that block. 我的想法是.NET有像TransactionScope这样的东西以某种方式检测离开该块时是否发生异常。 Is there I was I can leverage something like that to make a common try/catch block? 有没有我可以利用这样的东西来制作一个常见的try / catch块? Any other ideas? 还有其他想法吗?

I would do it like this: 我会这样做:

Create a method that contains the try/catch and pass an Action into it and execute that action inside the try part: 创建一个包含try / catch的方法并将Action传递给它并在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);
}

The two versions of SafeExecutor give you the possibility to handle methods with and without return types. SafeExecutor的两个版本使您可以处理带有和不带返回类型的方法。
Method1b shows that you don't need the variable action in your methods, you can inline it, if you think that's more readable. Method1b表明你不需要方法中的变量action ,如果你认为它更具可读性,你可以内联它。

there are ways in which you can do it easily - firstly for me I have started using AOP in order to catch my exceptions 有一些方法可以让你轻松完成 - 首先对我来说,我已经开始使用AOP来捕捉我的异常

this would effectively turn your code 这将有效地改变你的代码

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);
        }

into something like 变成类似的东西

[HandleException( Exception , FaultException<CustomException>, 
                      "Error Getting Details" )]
    public MYType GetDetails( string parameter )
    {
        //.... call to service
    }

using Postsharp - details here 使用Postsharp - 详情请点击此处

alternatively there is a blog post by Mark Rendle on how to catch exceptions in a Functional Programming way - i have not tried this one though 另外, Mark Rendle还有一篇关于如何以函数式编程方式捕获异常的博客文章 - 尽管如此,我还没有尝试过

You've identified a cross-cutting concern . 你已经确定了一个贯穿各领域的问题 You could employ an aspect-oriented programming (AOP) approach to this problem. 您可以采用面向方面编程(AOP)方法来解决此问题。 This can either be performed at runtime by using a proxy that sits in front of your class or during compilation by using an AOP tool that modifies the compiled code. 这可以通过使用位于类前面的代理或在编译期间使用修改编译代码的AOP工具在运行时执行。

In the past I've made use of Castle Dynamic Proxy to do this (at runtime). 在过去,我已经使用Castle Dynamic Proxy来执行此操作(在运行时)。 Alternatively you could use one of the other AOP frameworks such as PostSharp . 或者,您可以使用其他AOP框架之一,如PostSharp

If the parameters are same or close to the same you can always pass in a delegate. 如果参数相同或接近相同,则始终可以传入委托。 If they are not your could call the code by reflection and take a parameter of 'object[]' to pass to invoke. 如果它们不是你可以通过反射调用代码并使用'object []'参数传递给调用。

What you can do is write the above code in a method that takes a Action or a Func as a parameter which determines the method that should be called in the throw block, along with its parameters. 你可以做的是在一个方法中编写上面的代码,该方法将Action或Func作为参数来确定应该在throw块中调用的方法及其参数。

So that if you would call M(1, "string") in your throw block, it becomes DoStuff(M, 1, "string") 因此,如果您在throw块中调用M(1, "string") ,它将变为DoStuff(M, 1, "string")

DoStuff would look like DoStuff看起来像

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);
        }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM