.net 如何创建可重用的表达式树?

.net 如何创建可重用的表达式树?,.net,lambda,expression-trees,.net,Lambda,Expression Trees,我有一个表达式树: internal static IEnumerable<ElemType> WhereIn<ElemType>(this IEnumerable<ElemType> query, string filterFieldName, string[] values) { ParameterExpression lambdaParam = Expression.Parameter(typeof(ElemType),

我有一个表达式树:

    internal static IEnumerable<ElemType> WhereIn<ElemType>(this IEnumerable<ElemType> query, string filterFieldName, string[] values)
    {
        ParameterExpression lambdaParam = Expression.Parameter(typeof(ElemType), "p");
        MethodCallExpression paramToString = Expression.Call(Expression.PropertyOrField(lambdaParam, filterFieldName), typeof(object).GetMethod("ToString"));
        MethodInfo mi = typeof(Enumerable).GetMethods().Where(x => string.Equals(x.Name, "Contains", StringComparison.OrdinalIgnoreCase)).Single(x => x.GetParameters().Length == 2).MakeGenericMethod(typeof(string));
        Expression<Func<string[]>> array = () => values;
        MethodCallExpression contains = Expression.Call(mi, array.Body, paramToString);
        LambdaExpression lambdaExp = Expression.Lambda<Func<ElemType, bool>>(contains, lambdaParam);
        Func<ElemType, bool> lambda = (Func<ElemType, bool>)lambdaExp.Compile();

        return query.Where(lambda);
    }
内部静态IEnumerable,其中(此IEnumerable查询,字符串filterFieldName,字符串[]值)
{
ParameterExpression lambdaParam=表达式参数(typeof(ElemType),“p”);
MethodCallExpression paramToString=Expression.Call(Expression.PropertyOrField(lambdaram,filterFieldName),typeof(object.GetMethod(“ToString”);
MethodInfo mi=typeof(Enumerable).GetMethods().Where(x=>string.Equals(x.Name,“Contains”,StringComparison.OrdinalIgnoreCase)).Single(x=>x.GetParameters().Length==2.MakeGenericMethod(typeof(string));
表达式数组=()=>值;
MethodCallExpression包含=Expression.Call(mi,array.Body,paramToString);
LambdaExpression lambdaExp=Expression.Lambda(包含,lambdaParam);
Func lambda=(Func)lambdaExp.Compile();
返回查询.Where(lambda);
}
现在,当使用类似于
query.where(“propName”,newstring[]{“aaa”,“bbb”})的方法调用它时,
我并不总是希望代码创建一个新的表达式树,因为这样做非常耗时。但是
.Compile()
函数没有提供允许我使用已编译lambda的参数。(或者,更确切地说,我只是不知道如何正确地利用它。)


需要如何重写上面的表达式树才能缓存编译后的结果并为生成的编译lambda提供字符串数组?您应该创建并管理自己的缓存。
缓存的键应该是属性名。 关键概念是创建一个引用数组的闭包函数(curry函数)

这就是您在运行时需要创建的内容。
获取数组并返回与linq where函数的相同参数和返回类型匹配的其他函数的函数

public class ElemType
{
   public string MyProperty { get; set; }
}

static void Main(string[] args) {
    Expression<Func<string[], Func<ElemType, bool>>> exp = (arr) => (ElemType et) => arr.Contains(et.MyProperty);
    var compiled = exp.Compile();
    var func = compiled(new[] { "aaa", "bbb" });

    var query = new List<ElemType> { 
        new ElemType { MyProperty = "aaa" }, 
        new ElemType { MyProperty = "bbb" }, 
        new ElemType { MyProperty = "cccc" } 
    };

    var result = query.Where("MyProperty", new[] { "aaa", "bbb" });
} 
公共类元素类型
{
公共字符串MyProperty{get;set;}
}
静态void Main(字符串[]参数){
表达式exp=(arr)=>(ElemType et)=>arr.Contains(et.MyProperty);
var compiled=exp.Compile();
var func=已编译(新[]{“aaa”,“bbb”});
var query=新列表{
新的ElemType{MyProperty=“aaa”},
新的ElemType{MyProperty=“bbb”},
新的ElemType{MyProperty=“cccc”}
};
var result=query.Where(“MyProperty”,new[]{“aaa”,“bbb”});
} 
在运行时编译表达式树并使用属性名作为缓存键的完整解决方案

public class ElemType
{
    public string MyProperty { get; set; }
}

public static class ElemTypePropertySelector
{
    private static Dictionary<string, Func<string[], Func<ElemType, bool>>> dictionary = new Dictionary<string, Func<string[], Func<ElemType, bool>>>();

    public static IEnumerable<ElemType> WhereIn(this IEnumerable<ElemType> query, string filterFieldName, string[] values) {
        var cachedFactory = GetOrAdd(filterFieldName);
        var contains = cachedFactory(values);

        return query.Where(contains);
    }

    private static Func<string[], Func<ElemType, bool>> GetOrAdd(string filterFieldName) {
        Func<string[], Func<ElemType, bool>> cachedFunc;

        if (!dictionary.TryGetValue(filterFieldName, out cachedFunc)) {
            cachedFunc = CreateFactory(filterFieldName);
            dictionary.Add(filterFieldName, cachedFunc);
        }

        return cachedFunc;
    }

    private static Func<string[], Func<ElemType, bool>> CreateFactory(string filterFieldName) {
        MethodInfo mi = typeof(Enumerable).GetMethods().Where(x => string.Equals(x.Name, "Contains", StringComparison.OrdinalIgnoreCase)).Single(x => x.GetParameters().Length == 2).MakeGenericMethod(typeof(string));
        PropertyInfo pi = typeof(ElemType).GetProperty(filterFieldName);
        ParameterExpression arrExpression = Expression.Parameter(typeof(string[]), "arr");
        ParameterExpression rtParam = Expression.Parameter(typeof(ElemType), "et");
        var callExpression = Expression.Call(null, mi, new Expression[] { arrExpression, Expression.Property(rtParam, pi) });
        var innerExpression = Expression.Lambda<Func<ElemType, bool>>(callExpression, new[] { rtParam });
        var expression = Expression.Lambda<Func<string[], Func<ElemType, bool>>>(innerExpression, new ParameterExpression[] { arrExpression });

        return expression.Compile();
    }
}

class Program
{
    static void Main(string[] args) {
        var query = new List<ElemType> { 
            new ElemType { MyProperty = "aaa" }, 
            new ElemType { MyProperty = "bbb" }, 
            new ElemType { MyProperty = "cccc" } 
        };

        var result = query.WhereIn("MyProperty", new[] { "aaa", "bbb" });
    }
}
公共类元素类型
{
公共字符串MyProperty{get;set;}
}
公共静态类ElemTypePropertySelector
{
私有静态字典Dictionary=新字典();
公共静态IEnumerable,其中(此IEnumerable查询,字符串filterFieldName,字符串[]值){
var cachedFactory=GetOrAdd(filterFieldName);
var contains=cachedFactory(值);
返回查询。其中(包含);
}
私有静态Func GetOrAdd(字符串筛选器字段名称){
Func cachedFunc;
if(!dictionary.TryGetValue(filterFieldName,out cachedFunc)){
cachedFunc=CreateFactory(filterFieldName);
添加(filterFieldName,cachedFunc);
}
返回cachedFunc;
}
私有静态Func CreateFactory(字符串筛选器字段名称){
MethodInfo mi=typeof(Enumerable).GetMethods().Where(x=>string.Equals(x.Name,“Contains”,StringComparison.OrdinalIgnoreCase)).Single(x=>x.GetParameters().Length==2.MakeGenericMethod(typeof(string));
PropertyInfo pi=typeof(ElemType).GetProperty(filterFieldName);
ParameterExpression arexpression=Expression.Parameter(typeof(string[]),“arr”);
ParameterExpression rtParam=表达式参数(typeof(ElemType),“et”);
var callExpression=Expression.Call(null,mi,新表达式[]{arexpression,Expression.Property(rtParam,pi)});
var innerExpression=Expression.Lambda(callExpression,new[]{rtParam});
var expression=expression.Lambda(innerExpression,新参数expression[]{arexpression});
返回表达式.Compile();
}
}
班级计划
{
静态void Main(字符串[]参数){
var query=新列表{
新的ElemType{MyProperty=“aaa”},
新的ElemType{MyProperty=“bbb”},
新的ElemType{MyProperty=“cccc”}
};
var result=query.where(“MyProperty”,new[]{“aaa”,“bbb”});
}
}

您应该创建和管理自己的缓存。
缓存的键应该是属性名。 关键概念是创建一个引用数组的闭包函数(curry函数)

这就是您在运行时需要创建的内容。
获取数组并返回与linq where函数的相同参数和返回类型匹配的其他函数的函数

public class ElemType
{
   public string MyProperty { get; set; }
}

static void Main(string[] args) {
    Expression<Func<string[], Func<ElemType, bool>>> exp = (arr) => (ElemType et) => arr.Contains(et.MyProperty);
    var compiled = exp.Compile();
    var func = compiled(new[] { "aaa", "bbb" });

    var query = new List<ElemType> { 
        new ElemType { MyProperty = "aaa" }, 
        new ElemType { MyProperty = "bbb" }, 
        new ElemType { MyProperty = "cccc" } 
    };

    var result = query.Where("MyProperty", new[] { "aaa", "bbb" });
} 
公共类元素类型
{
公共字符串MyProperty{get;set;}
}
静态void Main(字符串[]参数){
表达式exp=(arr)=>(ElemType et)=>arr.Contains(et.MyProperty);
var compiled=exp.Compile();
var func=已编译(新[]{“aaa”,“bbb”});
var query=新列表{
新的ElemType{MyProperty=“aaa”},
新的ElemType{MyProperty=“bbb”},
新的ElemType{MyProperty=“cccc”}
};
var result=query.Where(“MyProperty”,new[]{“aaa”,“bbb”});
} 
在运行时编译表达式树并使用属性名作为缓存键的完整解决方案

public class ElemType
{
    public string MyProperty { get; set; }
}

public static class ElemTypePropertySelector
{
    private static Dictionary<string, Func<string[], Func<ElemType, bool>>> dictionary = new Dictionary<string, Func<string[], Func<ElemType, bool>>>();

    public static IEnumerable<ElemType> WhereIn(this IEnumerable<ElemType> query, string filterFieldName, string[] values) {
        var cachedFactory = GetOrAdd(filterFieldName);
        var contains = cachedFactory(values);

        return query.Where(contains);
    }

    private static Func<string[], Func<ElemType, bool>> GetOrAdd(string filterFieldName) {
        Func<string[], Func<ElemType, bool>> cachedFunc;

        if (!dictionary.TryGetValue(filterFieldName, out cachedFunc)) {
            cachedFunc = CreateFactory(filterFieldName);
            dictionary.Add(filterFieldName, cachedFunc);
        }

        return cachedFunc;
    }

    private static Func<string[], Func<ElemType, bool>> CreateFactory(string filterFieldName) {
        MethodInfo mi = typeof(Enumerable).GetMethods().Where(x => string.Equals(x.Name, "Contains", StringComparison.OrdinalIgnoreCase)).Single(x => x.GetParameters().Length == 2).MakeGenericMethod(typeof(string));
        PropertyInfo pi = typeof(ElemType).GetProperty(filterFieldName);
        ParameterExpression arrExpression = Expression.Parameter(typeof(string[]), "arr");
        ParameterExpression rtParam = Expression.Parameter(typeof(ElemType), "et");
        var callExpression = Expression.Call(null, mi, new Expression[] { arrExpression, Expression.Property(rtParam, pi) });
        var innerExpression = Expression.Lambda<Func<ElemType, bool>>(callExpression, new[] { rtParam });
        var expression = Expression.Lambda<Func<string[], Func<ElemType, bool>>>(innerExpression, new ParameterExpression[] { arrExpression });

        return expression.Compile();
    }
}

class Program
{
    static void Main(string[] args) {
        var query = new List<ElemType> { 
            new ElemType { MyProperty = "aaa" }, 
            new ElemType { MyProperty = "bbb" }, 
            new ElemType { MyProperty = "cccc" } 
        };

        var result = query.WhereIn("MyProperty", new[] { "aaa", "bbb" });
    }
}
公共类元素类型
{
公共字符串MyProperty{get;set;}
}
公共静态类ElemTypePropertySelector
{
私有静态字典Dictionary=新字典();
公共静态IEnumerable,其中(此IEnumerable查询,字符串filterFieldName,字符串[]值){
var cachedFactory=GetOrAdd(filterFieldName);
var contains=cachedFact