C# 如何使用ExpressionTree创建使用正则表达式的谓词

C# 如何使用ExpressionTree创建使用正则表达式的谓词,c#,regex,expression,predicate,C#,Regex,Expression,Predicate,我正在手动构建一个用于过滤CollectionView中的数据的谓词,我想添加通过用户提供的正则表达式过滤特定字段的功能。直接编写谓词会得到如下结果: string userRegex = "abc.+"; Predicate<object> myPredicate = p => Regex.IsMatch(((MyType).p).MyField, userRegex); string userRegex=“abc.+”; 谓词myPredicate=p=>Regex.Is

我正在手动构建一个用于过滤CollectionView中的数据的谓词,我想添加通过用户提供的正则表达式过滤特定字段的功能。直接编写谓词会得到如下结果:

string userRegex = "abc.+";
Predicate<object> myPredicate = p => Regex.IsMatch(((MyType).p).MyField, userRegex);
string userRegex=“abc.+”;
谓词myPredicate=p=>Regex.IsMatch(((MyType.p).MyField,userRegex);
因此,我可以将该模式传递到谓词工厂,并执行类似的操作(在我的脑海中,没有尝试过-不确定调用语法):

string userRegex=“abc.+”;
var paramObject=Expression.Parameter(typeof(object),“p”);
var paramMyType=Expression.TypeAs(paramObject,typeof(MyType));
var propMyField=Expression.Property(paramMyType,“MyField”);
var constRegex=Expression.Constant(userRegex);
var methodInfo=typeof(Regex).GetMethod(“IsMatch”,新类型[]{typeof(string),typeof(string)});
var params=新表达式[]{propMyField,constRegex}
var lamdaBody=Expression.Call(methodInfo,params);
var lamda=表达式.Lambda(lamdaBody,paramObject);
var myPredicate=新谓词(lamda.Compile());
但我的直觉告诉我,这将创建一个表达式,在每次调用谓词时,该表达式将从模式中重建正则表达式。这种直觉正确吗

如果我的直觉是正确的,那么在创建使用正则表达式的表达式之前是否可以预构建正则表达式?如果是,怎么做

或者,如果我完全偏离了轨道,该由谁来做呢

(我的呼叫语法是否正确??)


编辑

只是为了澄清一些事情

  • 我正在构建的谓词的目标是
    CollectionView.Filter
    ,因此签名必须是
    predicate
  • 尽管我在我的示例中只显示了一个正则表达式,但我实际(动态)构建的谓词还有许多其他子句。为清楚起见,其余部分已略去
  • 谓词本身只有在用户单击某些选项并按下按钮后才能生成。即使与其他UI活动相比,也很少这样做
  • 应用谓词时,它将应用于支持CollectionView的集合中的10000到20000(或更多)个对象
  • 我的程序中几乎没有其他正则表达式,因此我认为Filip对缓存最后15个模式的观察意味着我的直觉可能是错误的
  • 但我仍然想做一些类似于Filip的回答的事情,并以某种方式在我正在构建的表达式树中捕获正则表达式的编译版本

  • 这将只编译表达式的属性部分一次。希望这能对你有所帮助

    public static class PropertyGetter<T>
        {
            private static Dictionary<string, Func<T, string>> cache = new Dictionary<string, Func<T, string>>();
    
            public static Func<T, string> Get(string propertyName)
            {
                if (!cache.ContainsKey(propertyName))
                {
                    var param = Expression.Parameter(typeof(T));
                    Expression<Func<T, string>> exp = Expression.Lambda<Func<T, string>>(Expression.Property(param, propertyName),param);
                    cache[propertyName] = exp.Compile();
                }
                return cache[propertyName];
            }
    
            public static Predicate<object> GetPredicate(string propertyName, string pattern)
            {
                Func<T, string> getter = Get(propertyName);
                Regex regex = new Regex(pattern, RegexOptions.Compiled);
    
                return (obj) => regex.IsMatch(getter((T)obj));            }
        }
    
    公共静态类PropertyGetter
    {
    私有静态字典缓存=新字典();
    公共静态Func Get(字符串属性名称)
    {
    如果(!cache.ContainsKey(propertyName))
    {
    var param=表达式参数(typeof(T));
    Expression exp=Expression.Lambda(Expression.Property(param,propertyName),param);
    缓存[propertyName]=exp.Compile();
    }
    返回缓存[propertyName];
    }
    公共静态谓词GetPredicate(字符串属性名称,字符串模式)
    {
    Func getter=Get(propertyName);
    Regex Regex=newregex(模式,RegexOptions.Compiled);
    return(obj)=>regex.IsMatch(getter((T)obj));}
    }
    

    只要有对谓词的引用,它就会使用come正则表达式。但是最好的检查方法就是在一些测试数据上运行它,看看会得到什么。默认情况下,该方法缓存最近使用的15个静态正则表达式模式。因此,如果不超过限制,表达式实现就不应该重新编译整个过程。但最好的方法是尽可能多地测试,看看会发生什么。

    这将只编译一次表达式的属性部分。希望这能对你有所帮助

    public static class PropertyGetter<T>
        {
            private static Dictionary<string, Func<T, string>> cache = new Dictionary<string, Func<T, string>>();
    
            public static Func<T, string> Get(string propertyName)
            {
                if (!cache.ContainsKey(propertyName))
                {
                    var param = Expression.Parameter(typeof(T));
                    Expression<Func<T, string>> exp = Expression.Lambda<Func<T, string>>(Expression.Property(param, propertyName),param);
                    cache[propertyName] = exp.Compile();
                }
                return cache[propertyName];
            }
    
            public static Predicate<object> GetPredicate(string propertyName, string pattern)
            {
                Func<T, string> getter = Get(propertyName);
                Regex regex = new Regex(pattern, RegexOptions.Compiled);
    
                return (obj) => regex.IsMatch(getter((T)obj));            }
        }
    
    公共静态类PropertyGetter
    {
    私有静态字典缓存=新字典();
    公共静态Func Get(字符串属性名称)
    {
    如果(!cache.ContainsKey(propertyName))
    {
    var param=表达式参数(typeof(T));
    Expression exp=Expression.Lambda(Expression.Property(param,propertyName),param);
    缓存[propertyName]=exp.Compile();
    }
    返回缓存[propertyName];
    }
    公共静态谓词GetPredicate(字符串属性名称,字符串模式)
    {
    Func getter=Get(propertyName);
    Regex Regex=newregex(模式,RegexOptions.Compiled);
    return(obj)=>regex.IsMatch(getter((T)obj));}
    }
    

    只要有对谓词的引用,它就会使用come正则表达式。但是最好的检查方法就是在一些测试数据上运行它,看看会得到什么。默认情况下,该方法缓存最近使用的15个静态正则表达式模式。因此,如果不超过限制,表达式实现就不应该重新编译整个过程。但最好的方法是尽可能多地测试,看看会发生什么。

    首先,不清楚为什么要使用表达式树/动态代码生成。性能是否真的如此关键,以至于您无法创建复合
    谓词
    来连接其他(较小的)
    谓词
    s

    其次,我不确定我是否理解您在哪里看到了将代码更改为使用compiled
    RegEx
    的问题。以下代码是您想要的:

        static Predicate<object> CreateRegExPredicateSmart(string pattern)
        {
            var regex = new Regex(pattern, RegexOptions.Compiled);
            var paramObject = Expression.Parameter(typeof(object), "p");
            var paramMyType = Expression.TypeAs(paramObject, typeof(MyType));
            var propMyField = Expression.Property(paramMyType, "MyField");
            var constRegex = Expression.Constant(regex);
    
            var methodInfo = typeof(Regex).GetMethod("IsMatch", new Type[] { typeof(string) });
            var paramsEx = new Expression[] { propMyField };
    
            var lamdaBody = Expression.Call(constRegex, methodInfo, paramsEx);
            Expression<Func<object, bool>> lamdaSmart = Expression.Lambda<Func<object, bool>>(lamdaBody, paramObject);
    
            return new Predicate<object>(lamdaSmart.Compile());
        }
    
    静态谓词CreateRegePredicateSmart(字符串模式)
    {
    var regex=新的regex(模式,RegexOptions.Compiled);
    var paramObject=Expression.Parameter(typeof(object),“p”);
    弗吉尼亚州