Invoking Regex.IsMatch() inside a dynamic linq query

孤人 提交于 2019-12-04 06:28:02

问题


I'm trying to invoke the Regex.IsMatch() and evaluate the returned result inside a dynamic linq query. This is what I tried:

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

In this case Category is a property in the EventListItem. This exception is thrown upon calling ParseLambda():

Unknown identifier 'Regex'.

Is there a way to invoke the method? I came across Expression.Call() method, but I'm not sure if that's what I'm looking for. Any help is appreciated.


回答1:


I haven't used System.Linq.Dynamic a lot, but here is a way to make your example work:

1 - You really only have one input object, your EventListItem, so remove parameter2 (Regex):

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() is made to read properties and methods from the input object. Using methods on other classes (here: Regex.IsMatch() is limited to a small set of predefined classes, and by default Regex isn't one of them.

Therefore, we somehow need to make the parser realize that "Regex" is a class and not a property on EventListItem. Assuming you have included the DynamicLinq.cs file in your project, this can be done by adding Regex (and RegexOptions) to the internal ExpressionParser.predefinedTypes array:

static readonly Type[] predefinedTypes = {
    typeof(Object),
    typeof(Boolean),
    ...

    typeof(System.Text.RegularExpressions.Regex), 
    typeof(System.Text.RegularExpressions.RegexOptions),
};


EDIT: Complex parameter values
If we need to include more complex parameters in our method calls, e.g. a combined RegexOptions enum; RegexOptions.Compiled | RegexOptions.IgnoreCase, ParseLambda also accepts a list of values.

We prepare the combined enum beforehand, and submit it in that values list. In compilableExpression we include placeholders for the values we submit, indexed in the same order we submit them (here we only have one value - index 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);

Bonus: Because the RegexOptions class/enum is no longer directly referenced in compilableExpression, we also no longer need to include RegexOptions in ExpressionParser.predefinedTypes.



来源:https://stackoverflow.com/questions/16679722/invoking-regex-ismatch-inside-a-dynamic-linq-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!