代码之家  ›  专栏  ›  技术社区  ›  DooDoo

将包含转换为表达式树

  •  0
  • DooDoo  · 技术社区  · 7 年前

    Create a Lambda Expression With 3 conditions

    请考虑以下代码:

    from a in myTbl
    where a.Address.Contains(strToCheck)
    select a
    

    如何将其转换为表达式树并用表达式编写上述代码? a.Address.Contains(strToCheck) Expression Tree

    编辑1)地址是 string 字段和 strToCheck

    谢谢

    2 回复  |  直到 7 年前
        1
  •  3
  •   Ivan Stoev    7 年前

    a.Address.Contains(strToCheck) 呼叫 string.Contains 实例方法 a.Address 具有 strToCheck 论点

    构建相应表达式的最简单方法是使用以下公式 Expression.Call overload :

    public static MethodCallExpression Call(
        Expression instance,
        string methodName,
        Type[] typeArguments,
        params Expression[] arguments
    )
    

    这样(使用链接问题中的术语):

    var body = Expression.Call(
        Expression.PropertyOrField(param, "Address"), // instance
        "Contains", // method
        Type.EmptyTypes, // no generic type arguments
        Expression.Constant(strToCheck) // argument
    );
    
        2
  •  0
  •   Sagi    7 年前

    您没有指定myTbl的类型,
    因此,我创建了一个简单的解决方案,只使用一个对象列表。

    using System;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Collections.Generic;
    
    namespace Test
    {
        class Program
        {
            static void Main(string[] args) {
                var adresses = FilterByAddress("Address", new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } });
            }
    
            public static IEnumerable<Person> FilterByAddress(string strToCheck, List<Person> list) {
                var listParam = Expression.Parameter(typeof(IEnumerable<Person>), "list");
                Expression<Func<Person, bool>> contains = a => a.Address.Contains(strToCheck);
                var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
                var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) });
                var call = Expression.Call(null, genericMethod, new Expression[] { listParam, contains });
                var lambda = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>(call, new[] { listParam });
    
                return lambda.Compile().Invoke(list);
            }
        }
    
        public class Person
        {
            public string Address { get; set; }
        }
    }
    

    Expresssion<Func<Person, bool>> as参数(一行)

        static void Main(string[] args) {
            var strToCheck = "Address";
            var list = new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } };
            var adresses = FilterByAddress(list, p => p.Address.Contains(strToCheck));
        }
    
        public static IEnumerable<Person> FilterByAddress(List<Person> list, Expression<Func<Person, bool>> predicateEx) {
            var listParam = Expression.Parameter(typeof(IEnumerable<Person>), "list");
            var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
            var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) });
            var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx });
            var lambda = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>(call, new[] { listParam });
    
            return lambda.Compile().Invoke(list);
        }
    

    如果您有一个跨越多行的非常编译的谓词(可以从一行lambda计算表达式树),您可以使用以下技巧从谓词Func构建表达式树:

        static void Main(string[] args) {
            var strToCheck = "Address";
            Func<Person, bool> predicate = p => {
                return p.Address.Contains(strToCheck);
            };
    
            var list = new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } };
            var adresses = FilterByAddress(list, predicate);
        }
    
        public static IEnumerable<Person> FilterByAddress(List<Person> list, Func<Person, bool> predicate) {
            var listParam = Expression.Parameter(typeof(IEnumerable<Person>), "list");
            Expression<Func<Person, bool>> predicateEx = p => predicate(p);
            var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
            var genericMethod = select.MakeGenericMethod(new[] { typeof(Person) });
            var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx });
            var lambda = Expression.Lambda<Func<IEnumerable<Person>, IEnumerable<Person>>>(call, new[] { listParam });
    
            return lambda.Compile().Invoke(list);
        }
    

        static void Main(string[] args) {
            var strToCheck = "Address";
            Func<Person, bool> predicate = p => {
                return p.Address.Contains(strToCheck);
            };
    
            var list = new List<Person> { new Person { Address = "Address1" }, new Person { Address = "AAAAAA" } };
            var adresses = FilterBy<Person>(list, predicate);
        }
    
        public static IEnumerable<T> FilterBy<T>(List<T> list, Func<T, bool> predicate) {
            var listParam = Expression.Parameter(typeof(IEnumerable<T>), "list");
            Expression<Func<T, bool>> predicateEx = p => predicate(p);
            var select = typeof(Enumerable).GetMethods().Single(m => m.Name.Equals("Where") && m.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
            var genericMethod = select.MakeGenericMethod(new[] { typeof(T) });
            var call = Expression.Call(null, genericMethod, new Expression[] { listParam, predicateEx });
            var lambda = Expression.Lambda<Func<IEnumerable<T>, IEnumerable<T>>>(call, new[] { listParam });
    
            return lambda.Compile().Invoke(list);
        }
    }