2011-12-06 12 views
6

Tengo problemas para decidir la mejor forma de refactorizar un método que contiene consultas LINQ que son muy similares pero no idénticas.Método de refactorización que contiene consultas LINQ

Considere un método que es algo a lo largo de estas líneas:

public SomeObject GetTheObject(IMyObject genericObject) { 
    Type t = genericObject.GetType(); 
    SomeObject so = null; 

    switch(t.Name) { 
     case "Type1": 
      var object1 = (from o in object1s where o.object1id == genericObject.id).FirstOrDefault(); 
      so = (SomeObject)object1; 
     break; 
     case "Type2": 
      var object2 = (from o in object2s where o.object2id == genericObject.id).FirstOrDefault(); 
      so = (SomeObject)object2; 
     break; 
     default: 
     break; 
    } 

    return so; 
} 

Esto es sólo un ejemplo, pero imagino que estoy necesitando para ejecutar una consulta diferente (diferente, ya que utiliza una ObjectSet diferente, utiliza un poco diferentes campos (object1id vs object2id) y devuelve un tipo diferente. Aparte de eso, las consultas son las mismas.

¿Hay alguna manera sensata de refactorizar este tipo de método? Parece que me he perdido algo obvio. Tal vez tengo que usar el método exacto y no puedo evitar volver a escribir la consulta, solo se ¡ems como DEBO poder de alguna manera!

Cualquier punteros apreciado considerablemente

+0

lo probé con la reflexión, pero no pude pasar de la declaración de LINQ ("desde o en object1s donde o.object1id"). Debería buscar dinámicamente generar una declaración LINQ. – Graham

+0

Hola, Graham, esta sería sin duda una opción, excepto por el hecho de que estoy tratando de mantener el DAL encapsulado en un Repositorio , lo que me limita en los métodos que puedo usar para construir dinámicamente una consulta. Traté de construir una fábrica para devolver la instancia concreta del Repositorio que quería. Pero esto me dejó en una situación similar a la que le describí a Paolo, es decir, porque mi Repositorio requiere un tipo concreto de EntityObject, por lo que no puedo crear uno basado en una interfaz. – dougajmcdonald

Respuesta

4

Tal vez lo que ha simplificado el escenario, pero la parte mal olor de su función es el elenco de SomeObject. ¿No podría simplemente trabajar con interfaces y (si es necesario) emitir el resultado en el sitio de llamadas? Puede hacer que su Type1 y Type2 implementen una interfaz común donde id1 e id2 están expuestos como id, por ejemplo (o decorarlos si no controla Type1 y Type2)

I.e.

public static IMyObject GetTheObject(List<IMyObject> theList, int id) 
{ 
    var ret = (from o in theList 
     where o.id==id 
     select o).FirstOrDefault(); 

    return ret; 
} 

Por ejemplo, si usted tiene:

public interface IMyObject {int id {get;}} 

    public class Foo : IMyObject {public int id {get; set;}} 
    public class Bar : IMyObject {public int id {get; set;}} 

que puede hacer:

var l1 = new List<IMyObject>(){new Foo(){id=1}, new Foo(){id=2}}; 
var l2 = new List<IMyObject>(){new Bar(){id=1}, new Bar(){id=2}}; 

var obj1 = Test.GetTheObject(l1, 1); 
var obj2 = Test.GetTheObject(l2, 2); 

y emitir los objetos después de llamar a la función, si es necesario.

EDIT: si le pegan con objetos concretos y moldes, la mejor refactorización que podía llegar a es:

public static SomeObject GetTheObject(IMyObject genericObject) { 
    Type t = genericObject.GetType(); 

    Func<SomeObject, bool> WhereClause = null; 
    IEnumerable<SomeObject> objs = null; // IEnumerable<T> is covariant, 
         // so we can assign it both an IEnumerable<object1> 
         // and an IEnumerable<object2> (provided object1 and 2 are 
         // subclasses of SomeObject) 

    switch(t.Name) { 
     case "Type1": 
      WhereClause = o => ((Object1)o).object1id == genericObject.id;  
      objs = object1s; 
     break; 
     case "Type2": 
      WhereClause = o => ((Object2)o).object2id == genericObject.id;  
      objs = object2s; 
     break; 
    } 

    var ob = objs 
    .Where(WhereClause) 
    .FirstOrDefault(); 

    return (SomeObject)ob; 
} 
+0

Sí, creo que simplifiqué un poco las cosas, el problema que tendría al trabajar con interfaces es que mi consulta es en realidad una consulta en un repositorio genérico que requiere un tipo concreto. Esto significa que no puedo hacer el repositorio en este momento, lo que me está causando dolor. Podría suponer escribir otro repositorio donde T: IMyObject, en lugar de T: EntityObject está en este momento, pero parece demasiado exagerado, pero puede ser necesario. – dougajmcdonald

+0

@dougajmcdonald: la refactorización que pude encontrar no parece una mejora sobre la suya, pero al menos reduce la duplicación en el código de linq ... :) –

+0

gracias por eso, tendré una jugada cuando llegue una oportunidad el jueves, tenía la esperanza de alejarme de la lógica de conmutación, ya que en mi situación real podría tener 10-12 opciones y ¡preferiría no tapar la pantalla con declaraciones de casos!¡entonces otra vez podría ser la única opción! – dougajmcdonald