【问题标题】:Invoking Regex.IsMatch() inside a dynamic linq query在动态 linq 查询中调用 Regex.IsMatch()
【发布时间】:2013-05-21 21:24:27
【问题描述】:

我正在尝试调用 Regex.IsMatch() 并在动态 linq 查询中评估返回的结果。这是我尝试过的:

public static LambdaExpression Parse(SearchQuery query)
{
    string compilableExpression = "Regex.IsMatch(Category.ToLower(), \"\\bSomeCat\\b\", RegexOptions.Compiled) == true";

    ParameterExpression parameter1 = System.Linq.Expressions.Expression.Parameter(typeof(EventListItem));
    ParameterExpression parameter2 = System.Linq.Expressions.Expression.Parameter(typeof(Regex));

    return System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { parameter1, parameter2 }, null, compilableExpression);
}

在这种情况下,CategoryEventListItem 中的一个属性。调用ParseLambda()时抛出此异常:

Unknown identifier 'Regex'.

有没有办法调用该方法?我遇到了Expression.Call() 方法,但我不确定这是否是我正在寻找的。任何帮助表示赞赏。

【问题讨论】:

    标签: c# regex dynamic-linq


    【解决方案1】:

    我没有经常使用System.Linq.Dynamic,但这里有一种方法可以让您的示例工作:

    1 - 你真的只有一个输入对象,你的EventListItem,所以删除参数2(正则表达式):

    string compilableExpression = "Regex.IsMatch(Category.ToLower(), \"\\bSomeCat\\b\", RegexOptions.Compiled) == true";
    ParameterExpression parameter1 = System.Linq.Expressions.Expression.Parameter(typeof(EventListItem));
    return System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] { parameter1 }, null, compilableExpression);
    

    2 - DynamicExpression.ParseLambda() 用于从 输入对象 读取属性和方法。在其他类上使用方法(此处:Regex.IsMatch() 仅限于一小组预定义类,默认情况下 Regex 不是其中之一。

    因此,我们需要以某种方式让解析器意识到“Regex”是一个类,而不是 EventListItem 上的一个属性。假设您在项目中包含了 DynamicLinq.cs file,这可以通过将 Regex(和 RegexOptions)添加到内部 ExpressionParser.predefinedTypes 数组来完成:

    static readonly Type[] predefinedTypes = {
        typeof(Object),
        typeof(Boolean),
        ...
    
        typeof(System.Text.RegularExpressions.Regex), 
        typeof(System.Text.RegularExpressions.RegexOptions),
    };
    


    编辑:复杂参数值
    如果我们需要在方法调用中包含更复杂的参数,例如组合的 RegexOptions 枚举; RegexOptions.Compiled | RegexOptions.IgnoreCase,ParseLambda 也接受values 的列表。

    我们事先准备好组合枚举,并将其提交到该值列表中。在compilableExpression 中,我们包含了我们提交的值的占位符,按照我们提交它们的相同顺序进行索引(这里我们只有一个值 - 索引 0)

    var options = RegexOptions.Compiled | RegexOptions.IgnoreCase;
    string compilableExpression = "Regex.IsMatch(Category.ToLower(), \"\\bSomeCat\\b\", @0) == true";
    ParameterExpression parameter1 = SLE.Expression.Parameter(typeof(EventListItem));
    return SLD.DynamicExpression.ParseLambda(new[] { parameter1 },
                                             null,
                                             compilableExpression,
                                             options);
    

    奖励:因为 RegexOptions 类/枚举不再直接在 compilableExpression 中引用,我们也不再需要在 ExpressionParser.predefinedTypes 中包含 RegexOptions。

    【讨论】:

    • 如果我可以投票 5 次,我会的!我想出了一个解决方法,但这让我的生活更轻松。还有一件事,在传递RegexOptions时,我可以传递多个吗?我试过RegexOptions.Compiled | RegexOptions.IgnoreCase,但它说'(' or ',' expected。有什么想法吗?
    • @programmer93 - DynamicExpression 类不是一个成熟的 C# 解析器,因此它可能不理解该语法。我已经用解决方法更新了我的答案。
    • 非常感谢,我会玩得很开心的 :)
    • 有没有人在实施这个解决方案时遇到过这个异常?开发 LambdaExpression 后,我输入 .Where() 并得到以下信息:“LINQ to Entities 无法识别方法 'Boolean IsMatch(System.String, System.String)' 方法,并且该方法无法转换为存储表达式。”
    • @Ken - 该异常与动态 linq 无关,而是与 Linq2Entities 不知道如何将 Regex.IsMatch() 方法转换为 SQL 的事实有关。查看这篇文章和接受的答案:linq to entities doesn't recognize a method
    猜你喜欢
    • 2020-12-06
    • 1970-01-01
    • 2016-10-16
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-11
    • 1970-01-01
    相关资源
    最近更新 更多