简体   繁体   English

如何重构“使用”语句以避免代码重复?

[英]How to refactor “using” statement to avoid code duplication?

Let's suppose I have the following methods: 假设我有以下方法:

 public string GetSchedules(string request)
    {
        using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
        {
            return soapClient.GetSchedules(AuthenticationInfo, request);
        }
    }

    public string GetCountryList(string request)
    {
        using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
        {
            return soapClient.GetCountryList(AuthenticationInfo, request);
        }
    }

    public string GetCarriers(string request)
    {
        using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
        {
            return soapClient.GetCarriers(AuthenticationInfo, request);
        }
    }

As you can see the only different thing is the name of the method invoked. 如您所见,唯一不同的是所调用方法的名称。 How could I refactor these methods to apply "using" statement only once and avoid code duplication? 我该如何重构这些方法以仅应用一次“ using”语句并避免代码重复?

To me, what you have is fine, but if you want to factor those out you can use Func and lambdas. 对我来说,您所拥有的还可以,但是如果您要排除这些因素,则可以使用Func和lambdas。 Something along these lines: 遵循以下原则:

public string GetSchedules(string request)
{
    return Worker((c) => c.GetSchedules(AuthenticationInfo, request));
}

public string GetCountryList(string request)
{
    return Worker((c) => c.GetCountryList(AuthenticationInfo, request));
}

public string GetCarriers(string request)
{
    return Worker((c) => c.GetCarriers(AuthenticationInfo, request));
}

private string Worker(Func<SoapClientClassGoesHere, string> f)
{
    using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
    {
        return f(soapClient);
    }
}

Func<A, R> means "a function that takes an argument of type A and returns a value of type R " (and you can have Func<A, B, R> for a function that takes two arguments, etc.). Func<A, R>意思是“一个具有A类型参数并返回R类型值的函数”(对于具有两个参数的函数,您可以具有Func<A, B, R> 。)

More about Func<> and lambdas in this question and this question (and many more, it's a rich topic). 有关此问题此问题的更多信息,请参见Func<>和lambdas(还有很多,这是一个很丰富的主题)。

Here's a live example on ideone.com (a very silly live example, but it demonstrates the concept): 这是ideone.com上的一个实时示例 (一个非常愚蠢的实时示例,但它演示了这个概念):

using System;
using System.Collections.Generic;

class Foo {
    public string GetSchedules(string request)
    {
        return Worker((c) => c[request]);
    }

    public string GetCountryList(string request)
    {
        return Worker((c) => c[request].ToUpper());
    }

    public string GetCarriers(string request)
    {
        return Worker((c) => c[request].ToLower());
    }

    private string Worker(Func<Dictionary<string,string>, string> f)
    {
        var d = new Dictionary<string, string>();
        d.Add("1", "One");
        d.Add("2", "Two");
        d.Add("3", "Three");
        return f(d);
    }
}

public class Test
{
    public static void Main()
    {
        var f = new Foo();
        Console.WriteLine(f.GetSchedules("1"));
        Console.WriteLine(f.GetCountryList("1"));
        Console.WriteLine(f.GetCarriers("1"));
    }
}

There's really not much duplication there. 那里确实没有太多重复。 Still, 仍然,

public ServiceReference1.CustomDataTimetableToolKitServicesSoapClient NewClient()
{
    return new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint)
}

using (var client = NewClient()) {
    return soapClient.GetCountryList(AuthenticationInfo, request);
}

Also, since all of your methods take a string parameter and return a string , it would be easy to write a single method to call them all, passing the operation to call as a delegate. 另外,由于所有方法都带有一个string参数并返回一个string ,因此很容易编写一个方法来全部调用它们,并将操作作为委托传递给call。 Unfortunately, I don't have the time to write that for you right now. 不幸的是,我现在没有时间为您写这些。

You can use lambda function in such way: 您可以通过以下方式使用lambda函数:

public string GetCarriers(string request)
{
    return Get((authInfo, request) => soapClient.GetCarriers(authInfo, request), request);
}

...

public string Get(Func<AuthenticationInfo, string, string> action, string request) {
    using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
    {
        return action(AuthenticationInfo, request)
    }
}

I don't know if that compiles but you get the idea. 我不知道是否可以编译,但是您知道了。

Edit: As @Tim S. noticed, this code could probably be shorter: 编辑:正如@Tim S.所注意到的,此代码可能会更短:

public string GetCarriers(string request)
{
    return Get(soapClient.GetCarriers, request);
}

...

public string Get(Func<AuthenticationInfo, string, string> action, string request) {
    using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
    {
        return action(AuthenticationInfo, request)
    }
}

Edit 2: The client was out of scope. 编辑2:客户端超出范围。 So correct code is: 因此正确的代码是:

public string GetCarriers(string request)
{
    return Get((client, authInfo, request) => client.GetCarriers(authInfo, request));
}

...

public string Get(Func<ISoapClient, AuthenticationInfo, string, string> action, string request) {
    using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
    {
        return action(soapClient, AuthenticationInfo, request)
    }
}

If your Projekt isn't very big you could use the following (it's a bit messy and makes it easy to make a mistake): 如果您的Projekt不太大,则可以使用以下命令(这有点混乱,容易出错):

public string getX (string request, string x)
{
    using (var soapClient = new ServiceReference1.CustomDataTimetableToolKitServicesSoapClient(EndpointConfiguratioName, Endpoint))
    {
        switch (x)
        {
            case "schedules":
                return soapClient.GetSchedules(AuthenticationInfo, request);
                break;
            case "countryList":
                return soapClient.GetCountryList(AuthenticationInfo, request);
                break;
            case "carriers":
                return soapClient.GetCarriers(AuthenticationInfo, request);
                break;
            }
        }
    }
}

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

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