2013-11-24 1 views
1

у меня есть два метода называют 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, но кроме этого у них нет ничего общего.

Я хотел бы удалить дублирование, но я не уверен, как это сделать.

Любые предложения?

ответ

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% верно!)

0

Если вы посмотрите на логике, второй метод является частным случаем первого метода : если T что-то вроде Wrapper, сделайте что-нибудь еще (ObjectWrapperSerializer); в противном случае - обычная вещь (ObjectSerializer).

Итак, идея состоит в том, что вы хотите динамически решать, что делать во время выполнения, глядя на Т. Как вы это делаете? Отражение!

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% точный, но я надеюсь, что он укажет вам в правильном направлении.

Смежные вопросы