获取 Predicate<T> 属性信息

3

我有一个类似以下的接口:

public IEnumerable<IDocument> Search(Predicate<IDocument> predicate) { ... }

一个 IDocument 看起来像这样:

public interface IDocument 
{
    string Id {get; set;}
    string Title {get; set;}
    ...
}

我即将实现一个文档提供程序,需要分解谓词的内容并提取属性,以便为我们目前没有OR/M映射到的文档数据库制作SQL字符串。例如:我想知道用户是按ID还是按标题搜索,这样我就知道是否可以按ID搜索或者必须在标题上执行LIKE搜索。
我一直大量使用LINQ,但这是我第一次坐在管道的另一端......我已经阅读了一些有关表达式树和反射的文章,但是这些知识还没有完全掌握。我如何(如果可以)分解/反射谓词,以便获得参数列表,然后将它们连接成SQL字符串?我正在寻找类似于以下草图的东西:
public IEnumerable<IDocument> Search(Predicate<IDocument> predicate) 
{ 
    string id = DoSomeMagic(predicate, "Id");
    string title = DoSomeMagic(predicate, "Title");
    if (!string.isNullOrEmpty(id))
       ...make ID search
    else
       ...search by title
}

免责声明:此提供者是为一个内部遗留系统而设计的,该系统将在今年秋季被替换,因此使用内联SQL是一个合适的选择。 ;o)
3个回答

3

您不能使用谓词或委托来实现这一点。它们是编译的,不可能获取其背后的信息。您确实需要 Expression 树来实现此目的,但自行解析可能会很困难。最好使用 O/RM 工具。

例如,当您将 Expression 与 LINQ to SQL 结合使用时,构建搜索方法将变得非常简单:

public IEnumerable<Document> Search(
    Expression<Func<Document, bool>> predicate) 
{
    using (db = new DocumentDataContext())
    {
        return db.Documents.Where(predicate).ToArray();
    }
}

1

你不能轻易地反射谓词。也许你应该考虑将你的设计改为更特定的谓词接口或更临时的谓词类型:

    public interface IDocument 
    {
        string Id {get; set;}
        string Title {get; set;}
    }
    public class SearchCriteria
    {
        public Nullable<int> Id;
        public string Title;
    }
    public IEnumerable<IDocument> Search(SearchCriteria predicate)
    {
        if (predicate.Id.HasValue)
            //...make ID search
        else if (!string.IsNullOrEmpty(predicate.Title))
            //...search by title
        else
            // other kind of search
    }

将公共字段替换为属性,将搜索逻辑放在SearchCriteria中(例如.GetResult()或.GetSQLQuery()),这可能适合您的系统,假设您可以知道所有可用的搜索条件。


这就是我们决定要做的。我们应该构建的表达式树会变得非常复杂,因此我们放弃了谓词并采用了更简单明了的方法。 - flowerpowerdad

0

你需要将方法声明为接受Expression>类型的参数。这个Expression可以被内省(虽然它可以是很多不同的东西)。

尝试在LinqPad中运行以下代码(LinqPad提供了Dump扩展方法,可以很好地可视化表达式)

void Main()
{
    show(x=>x.Length==5);
}

void show(Expression<Predicate<string>> e){
    e.Dump();
}

您可以通过首先调用Compile来执行一个表达式


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接