【问题标题】:Refactoring method containing LINQ queries包含 LINQ 查询的重构方法
【发布时间】:2011-12-06 13:48:18
【问题描述】:

我在决定重构包含非常相似但不相同的 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;
}

这只是一个说明,但想象一下我需要执行不同的查询(不同之处在于它使用不同的 ObjectSet,使用略有不同的字段(object1id 与 object2id)并返回不同的类型。 除此之外,查询是相同的。

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

非常感谢任何指针

【问题讨论】:

  • 我尝试使用反射,但无法通过 LINQ 语句(“from o in object1s where o.object1id”)。您应该研究动态生成 LINQ 语句。
  • 嗨格雷厄姆,这肯定是一个选择,除了我试图将 DAL 封装在存储库中的事实之外一个问题。我试图建立一个工厂来返回我想要的具体 Repository 实例。但这让我陷入了与 Paolo 描述的类似情况,即因为我的 Repository 需要一个具体的 EntityObject 类型,所以我无法基于接口创建一个。

标签: c# asp.net linq refactoring


【解决方案1】:

也许您只是过度简化了您的场景,但您的函数中令人讨厌的部分是对 SomeObject 的强制转换。您不能只使用接口并(如果需要)在调用站点上转换结果吗?例如,您可以让您的 Type1 和 Type2 实现一个通用接口,其中 id1 和 id2 作为 id 公开(或者如果您不控制 Type1 和 Type2,则装饰它们)

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

【讨论】:

  • 是的,我认为我确实简化了一些事情,使用接口时遇到的问题是我的查询实际上是对需要具体类型的通用存储库的查询。这意味着我现在不能做 Respository 这让我很伤心。我可以假设编写另一个存储库,其中 T:IMyObject,而不是目前的 T:EntityObject,但这感觉有点矫枉过正,但可能需要它。
  • @dougajmcdonald:我能想出的重构看起来不像你的有很大的改进,但至少它减少了 linq 代码中的重复...... :)
  • 谢谢,周四有机会我会玩,我希望摆脱切换逻辑,因为在我的现实生活中我可能有 10-12 个选项,我'宁愿不要用案例陈述把屏幕搞砸!那么它可能是唯一的选择!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
  • 1970-01-01
  • 2020-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
相关资源
最近更新 更多