【问题标题】:Linq based generic alternate to Predicate<T>?基于 Linq 的泛型替代 Predicate<T>?
【发布时间】:2011-02-16 13:07:00
【问题描述】:

我有一个名为ICatalog 的接口,如下所示,其中每个ICatalog 都有一个名称和一个方法,该方法将基于Predicate&lt;Item&gt; 函数返回项目。

public interface ICatalog
{
     string Name { get; }
     IEnumerable<Item> GetItems(Predicate<Item> predicate);
}

目录的特定实现可以链接到各种格式的目录,例如 XML 或 SQL 数据库。

使用 XML 目录,我最终将整个 XML 文件反序列化到内存中,因此使用谓词函数测试每个项目不会增加更多开销,因为它已经在内存中。

但对于 SQL 实现,我宁愿不将数据库的全部内容检索到内存中,然后使用谓词函数过滤项目。相反,我想找到一种方法以某种方式将谓词传递给 SQL 服务器,或者以某种方式将其转换为 SQL 查询。

这似乎是一个可以用 Linq 解决的问题,但我对它很陌生。我的界面应该返回 IQueryable 吗?我现在不关心如何实际实现我的 Icatalog 的 SQL 版本。我只是想确保我的界面将来可以使用它。

【问题讨论】:

    标签: c# .net linq iqueryable


    【解决方案1】:

    Rob 指出了您可以如何做到这一点(尽管更经典的 LINQ 方法可能采用 Expression&lt;Func&lt;Item,bool&gt;&gt;,并可能返回 IQueryable&lt;IFamily&gt;)。

    好消息是,如果您想将谓词与 LINQ-to-Objects 一起使用(对于您的 xml 场景),您可以使用:

    Predicate<Item> func = predicate.Compile();
    

    或(对于另一个签名):

    Func<Item,bool> func = predicate.Compile();
    

    并且您有一个委托 (func) 来测试您的对象。

    问题在于,这是单元测试的噩梦 - 你只能真正集成 测试它。

    问题是您不能可靠地模拟(使用 LINQ-to-Objects)任何涉及复杂数据存储的东西;例如,以下内容在您的单元测试中可以正常工作,但不能针对数据库“真正”工作:

    var foo = GetItems(x => SomeMagicFunction(x.Name));
    
    static bool SomeMagicFunction(string name) { return name.Length > 3; } // why not
    

    问题是只有一些操作可以翻译成TSQL。 IQueryable&lt;T&gt; 会遇到同样的问题——例如,EF 和 LINQ-to-SQL 支持对查询的不同操作;即使只是 First() 的行为也不同(EF 要求您先明确订购它,而 LINQ-to-SQL 则不需要)。

    总结一下:

    • 它可以工作
    • 但要仔细考虑是否要这样做;更经典的黑盒存储库/服务接口可能更具可测试性

    【讨论】:

    • 感谢马克的回答。听起来更复杂,然后我想要我正在尝试做的事情。 “更经典的黑盒存储库/服务接口”是什么意思?你能举个例子吗?
    【解决方案2】:

    您无需一路创建IQueryable implementation

    如果您将 GetItems 方法声明为:

    IEnumerable<IFamily> GetItems(Expression<Predicate<Item>> predicate);
    

    然后您的实现类可以检查表达式以确定要询问的内容。

    尽管阅读 IQueryable 文章,因为它解释了如何构建表达式树访问器,您需要构建一个简单的版本。

    【讨论】:

    • 仅供参考:我搞砸了原始示例,它应该同时使用 IEnumerable 和 Predicate 而不是 IEnumerable
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-13
    • 2017-11-18
    • 1970-01-01
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多