在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。运行结果如下:
结果报错了,说明没有想象的那么简单。原因是即便我的命名是相同的,都是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();
从运行结果来看,是没问题的
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();
运行结果相同: