如何重构相似的方法,以消除重复的设置和异常处理?

时间:2019-07-15 13:22:30

标签: c# generics reflection refactoring

上下文:

我使用的ERP WebService公开了N种方法,例如:

FunctionNameResponse FunctionName(FunctionNameQuery query)

我做了一个功能性包装,目的是:

  • 摆脱每种方法都具有的包装对象FunctionNameResponseFunctionNameQuery
  • 所有程序的一个WebService实例。
  • 调查并记录包装程序中的错误。
  • 使用IClientMessageInspector
  • 调查慢速运行和肥皂信封


重复的代码:

对于WebService的每种方法,我最终得到大约三十行代码,只有3个不同的词。输入响应,输入查询,方法名称。

public FooResponse Foo(FooQuery query)  
{  
    // CheckWebServiceState();  
    FooResponse result = null;  
    try  
    {   
        result =  
                WSClient  
                .Foo(query)  
                .response;  
    }  
    catch (Exception e)  
    {  
        // SimpleTrace();  
        // SoapEnvelopeInterceptorTrace();                 
        // TimeWatch_PerformanceIEndpointBehaviorTrace();  
    }  
    return result;
}

我想减少重复。为了:

  • 使添加方法更加容易;
  • 避免进行复制粘贴编程,而无需了解您在做什么。
  • 更容易添加特定的捕获和新的测试,而无需复制每种方法。

以下代码有效,并且仅存在于虚构领域中。根据我的有限理解,这不是我的解决方案的功能概述。

public class Demo
{
    public enum WS_Method
    {
        Foo,Bar,FooBar
    }
    public class temp
    {
        public Type Query { get; set; }
        public Type Response { get; set; }
        public WS_Method MethodName { get; set; }
    }
    public static IEnumerable<temp> TestFunctions =>
        new List<temp>
        {
            new temp{Query=typeof(FooQuery), Response=typeof(FooResponse), MethodName=WS_Method.Foo },
            new temp{Query=typeof(BarQuery), Response=typeof(BarResponse), MethodName=WS_Method.Bar },
            new temp{Query=typeof(FooBarQuery), Response=typeof(FooBarResponse), MethodName=WS_Method.FooBar },
        };
    public static void Run()
    {   // Exemple of consuming the method 
        var input = new BarQuery { Bar_Label = "user input", Bar_Ig = 42 };

        BarResponse result = Execute<BarQuery, BarResponse>(input);
    }
    public static T2 Execute<T1,T2>(T1 param) {
        //Get temp line where Query type match Param Type.
        var temp = TestFunctions.Single(x => x.Query == typeof(T1));
        var method = typeof(DemoWrapper).GetMethod(temp.MethodName.ToString(), new Type[] { typeof(T1) });
        var wsClient = new DemoWrapper();

        T2 result = default(T2);
        try
        {
            result =
                    method
                        .Invoke(wsClient, new object[] { param })
                        .response;
        }
        catch (Exception e)
        {
            // SimpleTrace();
            // SoapEnvelopeInterceptorTrace();               
            // TimeWatch_PerformanceIEndpointBehaviorTrace();
        }

        return result;
    }

}

我知道反射很重,也许这不是实现此重构的正确方法。所以问题是:

如何重构这些功能?

附件:实时演示https://dotnetfiddle.net/aUfqNp

2 个答案:

答案 0 :(得分:2)

在这种情况下:

  • 您有一个较大的代码块,通常重复出现
  • 唯一的区别是在较大的块内调用了较小的代码单元

您可以通过将较小的代码单元作为FuncAction作为参数传递给较大的函数来重构它。

在这种情况下,较大的函数如下所示:

public TResponse GetResponse<TResponse>(Func<TResponse> responseFunction)
{
    var result = default(TResponse);
    try
    {
        result = responseFunction();
    }
    catch (Exception e)
    {
        // SimpleTrace();  
        // SoapEnvelopeInterceptorTrace();                 
        // TimeWatch_PerformanceIEndpointBehaviorTrace();  
    }
    return result;
}

调用它的各个函数看起来像这样,而没有所有重复的代码:

public FooResponse Foo(FooQuery query)
{
    return GetResponse(() => WSClient.Foo(query));
}

答案 1 :(得分:1)

这是另一种方法,其中保留方法,但让它们全部调用处理重复的方法。

public class Demo
{
    private _wsClient = new DemoWrapper();

    public static void Run()
    {   // Exemple of consuming the method 
        var input = new BarQuery { Bar_Label = "user input", Bar_Ig = 42 };

        BarResponse result = Bar(input);
    }

    public FooResponse Foo(FooQuery foo) =>
        Execute(foo, query => _wsClient.Foo(query));

    public BarResponse Bar(BarQuery bar) =>
        Execute(bar, query => _wsClient.Bar(query));

    public FooBarResponse FooBar(FooBarQuery fooBar) =>
        Execute(fooBar, query => _wsClient.FooBar(query));

    private static TResponse Execute<TQuery ,TResponse>(
        TQuery param, Func<TQuery, TResponse> getResponse) 
    {
        //Get temp line where Query type match Param Type.
        var result = default(TResponse);
        try
        {
            result = getResponse(query);
        }
        catch (Exception e)
        {
            // SimpleTrace();
            // SoapEnvelopeInterceptorTrace();               
            // TimeWatch_PerformanceIEndpointBehaviorTrace();
        }

        return result;
    }
}