C#中合并两个lambda表达式

在LINQ中如何查询条件不固定,如何合并两个lambda表达式?其中一个方式是LINQ.Dynamic,关于LINQ.Dynamic的简单使用可以参考这篇文章,还有一种方法是利用Expression表达式树,有关表达式树的介绍,可以看这篇文章。

测试代码如下:

public class Phone
{
     public string Country { get; set; }
     public string City { get; set; }
     public string Name { get; set; }
}
public class Person
{
      public string Name { get; set; }
      public string Gender { get; set; }
      public int Age { get; set; }
      public List Phones { get; set; }

}
static void Main(string[] args)
{
            List PersonLists = new List()
            {
                new Person { Name = "张三",Age = 20,Gender = "男",
                    Phones = new List {
                        new Phone { Country = "中国", City = "北京", Name = "小米" },
                        new Phone { Country = "中国",City = "北京",Name = "华为"},
                        new Phone { Country = "中国",City = "北京",Name = "联想"},
                        new Phone { Country = "中国",City = "台北",Name = "魅族"},
                        }
                },
                new Person { Name = "松下",Age = 30,Gender = "男",
                    Phones = new List {
                        new Phone { Country = "日本",City = "东京",Name = "索尼"},
                        new Phone { Country = "日本",City = "大阪",Name = "夏普"},
                        new Phone { Country = "日本",City = "东京",Name = "松下"},
                    }
                },
                new Person { Name = "克里斯",Age = 40,Gender = "男",
                    Phones = new List {
                        new Phone { Country = "美国",City = "加州",Name = "苹果"},
                        new Phone { Country = "美国",City = "华盛顿",Name = "三星"},
                        new Phone { Country = "美国",City = "华盛顿",Name = "HTC"}
                    }
                }
            };

            Expression> lambdaone = ex => ex.Name.Equals("张三");
            Expression> lambdatwo = ex => ex.Age == 30;
            ParameterExpression pa = Expression.Parameter(typeof(Person), "ex");
            Expression> newEx = Expression.Lambda>(Expression.Or(lambdaone.Body, lambdatwo.Body), pa);
            var Lists = PersonLists.Where(newEx.Compile());
            Console.WriteLine();
            Console.Read();
}

 在上述代码中,我要构建一个满足两个条件的过滤查询:名字叫张三或者年龄是30。运行结果如下:

C#中合并两个lambda表达式_第1张图片

结果报错了,说明没有想象的那么简单。原因是即便我的命名是相同的,都是ex,但是两个表达式本质并不是相同的参数ex ,我只是引用了两个不同parameter的lambda表达式的body,然后将这两个body强行给了另一个parameter,具体信息可以这篇文藏

这时候我们需要重写ExpressionVisitor,代码如下:

    public class MyExpressionVisitor : ExpressionVisitor
    {
        public ParameterExpression _Parameter { get; set; }

        public MyExpressionVisitor(ParameterExpression Parameter)
        {
            _Parameter = Parameter;
        }
        protected override Expression VisitParameter(ParameterExpression p)
        {
            return _Parameter;
        }

        public override Expression Visit(Expression node)
        {
            return base.Visit(node);//Visit会根据VisitParameter()方法返回的Expression修改这里的node变量
        }
    }

修改调试代码如下:

Expression> lambdaone = ex => ex.Name.Equals("张三");
Expression> lambdatwo = ex => ex.Age == 30;
ParameterExpression pa = Expression.Parameter(typeof(Person), "ex");
MyExpressionVisitor visitor = new MyExpressionVisitor(pa);//统一参数类型
Expression bodyone = visitor.Visit(lambdaone.Body);
Expression bodytwo = visitor.Visit(lambdatwo.Body);
Expression> newEx = Expression.Lambda>(Expression.Or(bodyone, bodytwo), pa);
var Lists = PersonLists.Where(newEx.Compile());
foreach (var List in Lists)
{
    Console.WriteLine(List.Name);
}
Console.Read();

从运行结果来看,是没问题的

C#中合并两个lambda表达式_第2张图片

 

第二种方式是利用Expression.Invoke() ,代码如下:

Expression> lambdaone = ex => ex.Name.Equals("张三");
Expression> lambdatwo = ex => ex.Age == 30;
// 创建参数表达式
InvocationExpression invocation = Expression.Invoke(lambdaone, lambdatwo.Parameters.Cast());
// 创建or运算
BinaryExpression binary = Expression.Or(lambdatwo.Body, invocation);
// 生成lambda表达式
var exp = Expression.Lambda>(binary, lambdatwo.Parameters);
var Lists = PersonLists.Where(exp.Compile());
foreach (var List in Lists)
{
     Console.WriteLine(List.Name);
}
Console.Read();

运行结果相同:

C#中合并两个lambda表达式_第3张图片

 

你可能感兴趣的:(C#学习)