2011-12-06 59 views
6

我在决定重构包含非常相似但不完全相同的LINQ查询的方法的最佳方法时遇到了一些麻烦。包含LINQ查询的重构方法

考虑这东西沿着这些路线的方法:

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; 
} 

这只是一个例子,但是想象一下,我需要执行不同的查询(因为它使用不同的对象集不同,稍微使用不同的字段(object1id和object2id)并返回不同的类型 除此之外,查询是相同的

有没有一种明智的方法来重构这种方法?感觉就像我错过了一些明显的东西。也许我必须使用确切的方法,我无法避免重写查询,它只是ems像我应该能够以某种方式!

任何指针十分赞赏

+0

我尝试了与反思,但不能让过去的LINQ语句( “从o的object1s where o.object1id”)。你应该看看动态生成一个LINQ语句。 – Graham

+0

嗨格雷厄姆,这肯定是一个选择,除了我试图保持封装在存储库中的DAL ,这使我受限于我可以用来动态构建查询的方法。我试图建立一个工厂来返回我想要的具体Repository实例。但是这给我留下了类似于Paolo所描述的情况,即因为我的Repository需要一个具体的EntityObject类型,所以我不能根据接口创建一个。 – dougajmcdonald

回答

4

也许你刚才过于简化您的方案,但你的函数的臭一部分是投给SomeObject。难道你不能只使用接口和(如果需要)在调用站点上投射结果吗?例如,你可以让你的Type1和Type2实现一个公共接口,其中id1和id2公开为id(或者如果你不控制Type1和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; 
} 

举例来说,如果您有:

public interface IMyObject {int id {get;}} 

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

你可以这样做:

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); 

你调用该函数后,如果你要投的对象。

编辑: 如果你坚持具体对象和铸件,我能想出的最好的重构是:

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

是的,我认为我确实简化了一些东西,我在处理接口时遇到的问题是我的查询实际上是对需要具体类型的通用存储库的查询。这意味着我目前无法做Respository ,这引起了我的悲痛。 我想我可以写另一个T:IMyObject的仓库,而不是现在的T:EntityObject,但是这感觉像是矫枉过正,但可能需要它。 – dougajmcdonald

+0

@dougajmcdonald:我可以想出的重构看起来不像你的改进太多,但至少减少了linq代码中的重复... :) –

+0

谢谢你,我会得到一个玩,当我得到一个周四的机会,我希望摆脱切换逻辑,就像我现实生活中的情况一样,我可能有10-12个选项,而且我宁愿不要用case语句将屏幕提起来!那么它可能是唯一的选择! – dougajmcdonald