删除看起来相同但适用于不同类型的方法中的代码重复

时间:2013-11-24 13:36:22

标签: c# code-duplication

我有两个名为Run的方法看起来几乎相同,但它们使用不同的类型:

public string Run<T>(IEnumerable<T> items) 
{
    // ... Code

    var serializer = new ObjectSerializer<T>();
    var headers = serializer.SerializeHeaders(items);

    // ... Code

    foreach (var item in items)
    {
        var values = serializer.SerializeValues(item);

        // ... Code
    }

    // ... Code
}


public string Run<T>(IEnumerable<Wrapper<T>> items) 
{
    // ... Code

    var serializer = new ObjectWrapperSerializer<T>();
    var headers = serializer.SerializeHeaders(items);

    // ... Code

    foreach (var item in items)
    {
        var values = serializer.SerializeValues(item);

        // ... Code
    }

    // ... Code
}

public class ObjectSerializer<T>
{
    public string[] SerializeHeaders(IEnumerable<T> items) { ... }
    public string SerializeValues(T item) { ... }
}

public class ObjectWrapperSerializer<T>
{
    public string[] SerializeHeaders(IEnumerable<Wrapper<T>> items) { ... }
    public string SerializeValues(Wrapper<T> item) { ... }
}

两种方法中的所有// ... Code部分都相同。 Wrapper<T>有一个T的实例,但除此之外,它们没有任何共同之处。

我想删除重复,但我不知道该怎么做。

有什么建议吗?

2 个答案:

答案 0 :(得分:3)

如果唯一不同的是所需的序列化程序,您可以将其作为参数传递吗?像这样:

public class Runner    
{
    private string Run<T>(IEnumerable<T> items, IObjectSerializer<T> serializer) 
    {
        // ... Code

        var headers = serializer.SerializeHeaders(items);

        // ... Code

        foreach (var item in items)
        {
            var values = serializer.SerializeValues(item);

            // ... Code
        }

        // ... Code
    }

    public string Run<T>(IEnumerable<T> items)
    {
        return Run(items, new ObjectSerializer<T>());
    }

    public string Run<T>(IEnumerable<Wrapper<T>> items)
    {
        return Run(items, new ObjectWrapperSerializer<T>());
    }
}        
public interface IObjectSerializer<T>
{
    string[] SerializeHeaders(IEnumerable<T> items);
    string SerializeValues(T item);
}

public class ObjectSerializer<T>: IObjectSerializer<T>
{
    public string[] SerializeHeaders(IEnumerable<T> items) { ... }
    public string SerializeValues(T item) { ... }
}

public class ObjectWrapperSerializer<T> : IObjectSerializer<Wrapper<T>>
{
    public string[] SerializeHeaders(IEnumerable<Wrapper<T>> items) { ... }
    public string SerializeValues(Wrapper<T> item) { ... }
}

(还没有Visual Studio,所以可能不是100%正确!)

答案 1 :(得分:0)

如果你看一下你的逻辑,第二种方法是第一种方法的一个特例:如果T就像Wrapper那样,做其他事情(ObjectWrapperSerializer);否则做正常的事情(ObjectSerializer)。

所以这个想法是,你想通过查看T来动态决定在运行时做什么。你怎么做?反射!

if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(Wrapper<>)){
    Type u = typeof(T).GetGenericArguments()[0]; //u is the type in Wrapper<U>
    MethodInfo method = TheGenericWrapperMethod;
    MethodInfo gMethod = method.MakeGenericMethod(new Type[] { u });
    gMethod.Invoke();
} else {
    //do the normal thing
}

或者,您可以查看工厂模式:创建一个工厂类,它在运行时生成ObjectSerializer或ObjectWrapperSeralizer实例(当然,您必须具有某种类型的契约,如继承或接口或抽象类等)。

代码不是100%准确,但我希望它会指向正确的方向。