Expression表达式树--无聊写了个表达式树的小轮子用于日常使用
在刚开始敲代码的时候遇到过这样的事:查询条件多,查询条件不唯一,这个时候需要我们去写非常多的if-else 以及在where写冗长的lamada式
这时候我们可以通过Expression构建动态表达式树来生成所谓的lamada表达式
附上教程;https://ldqk.xyz/1795?kw=%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%A0%91
public class Student
{
[Expression(Wheretype.Equal,Logictype.And)]
public string Banji { get; set; }
[Expression(Wheretype.Equal, Logictype.And)]
public string id { get; set; }
[Expression(Wheretype.Like, Logictype.And)]
public string name { get; set; }
[Expression(Wheretype.Equal, Logictype.And)]
public string url { get; set; }
[Expression(Wheretype.Equal, Logictype.And)]
public string txtName { get; set; }
public static string Sayname(string name) {
return "我叫" + name;
}
}
自定义特性
点击查看代码
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Enum|AttributeTargets.Property)]
public class ExpressionAttribute:Attribute
{
public Logictype logictype{ get; set; }//And 0r
public Wheretype ExpressionName { get { return expre; } }//Equeal、Like
private Wheretype expre { get; set; }
public ExpressionAttribute(Wheretype wheretype,Logictype logictype1) {
expre = wheretype;
logictype = logictype1;
}
public int SwitchType() {
if (expre == Wheretype.Equal && logictype == Logictype.And)
return 1;
if (expre == Wheretype.Equal && logictype == Logictype.Or)
return 2;
if (expre == Wheretype.Like && logictype == Logictype.And)
return 3;
if (expre == Wheretype.Like && logictype == Logictype.Or)
return 4;
return 0;
}
}
public enum Wheretype
{
Equal,
Like
}
public enum Logictype
{
And,
Or
}
构建的表达式树泛型类
点击查看代码
public class ExpressionBuilder<TEntity>
{
private ParameterExpression para;
private TEntity entity1;
public ExpressionBuilder(TEntity entity){
para = Expression.Parameter(typeof(TEntity),"T");
this.entity1 = entity;
}
public BinaryExpression whereAlso =Expression.And(Expression.Constant(true),Expression.Constant(true));
public Expression Equal(string filed)
{
var value= GetVlaue(filed);
if (value == null)
return null;
var prop = Expression.Property(para, filed);
var eq = Expression.Equal(prop, Expression.Constant(value, value.GetType()));
return eq;
}
public Expression LessThan(string filed)
{
var value = GetVlaue(filed);
if (value is null)
return null;
var prop = Expression.Property(para, filed);
var lessthan = Expression.LessThan(prop, Expression.Constant(value));
return lessthan;
}
public Expression MoreThan(string filed)
{
var value = GetVlaue(filed);
if (value is null)
return null;
var prop = Expression.Property(para, filed);
var morethan = Expression.GreaterThan(prop, Expression.Constant(value));
return morethan;
}
public Expression MoreThanEqual(string filed)
{
var value = GetVlaue( filed);
if (value is null)
return null;
var prop = Expression.Property(para, filed);
var morethan = Expression.GreaterThanOrEqual(prop, Expression.Constant(value));
return morethan;
}
public Expression Like(string filed)
{
var value = GetVlaue(filed);
if (value == null)
return null;
var prop = Expression.Property(para,filed);
var method = typeof(String).GetMethod("Contains", new[] { typeof(string) });
var call = Expression.Call(prop, method, Expression.Constant(value));
return call;
}
/// <summary>
/// 获取实体属性值
/// </summary>
/// <param name="entity"></param>
/// <param name="filed"></param>
/// <returns></returns>
public object GetVlaue(string filed) {
var props = typeof(TEntity).GetProperties();
if (!props.Select(p => p.Name).ToList().Contains(filed))
return null;
return props.Where(p => p.Name == filed).FirstOrDefault().GetValue(this.entity1);
}
public void And(Expression bianEx) {
if (bianEx != null)
this.whereAlso = Expression.AndAlso(whereAlso, bianEx);
}
/// <summary>
/// 创建lamada委托表达式
/// </summary>
/// <returns></returns>
public Expression<Func<TEntity,bool>> CreateLamada()
{
if (this.whereAlso != null)
return Expression.Lambda<Func<TEntity, bool>>(this.whereAlso, para);
return null;
}
public void Or(Expression expression) {
if (expression != null)
this.whereAlso = Expression.OrElse(this.whereAlso, expression);
}
/// <summary>
/// 全匹配
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public Expression<Func<TEntity, bool>> Catchall()
{
ParameterExpression para = Expression.Parameter(typeof(TEntity), "t");
if (this.entity1 == null)
return null;
BinaryExpression whereExpression = Expression.And(Expression.Constant(true), Expression.Constant(true));
var props = typeof(TEntity).GetProperties();
Expression expre = null;
foreach (var item in props)
{
if (item.GetValue(this.entity1) is null)//过滤空值属性
continue;
var attr = item.GetCustomAttributes().ToArray()[0] as ExpressionAttribute;
var prop = Expression.Property(para, item.Name);
var method = typeof(String).GetMethod("Contains", new[] { typeof(string) });
switch (attr.SwitchType()) {
case 1:
expre= Expression.Equal(prop, Expression.Constant(item.GetValue(this.entity1)));
whereExpression = Expression.And(whereExpression, expre);
break;
case 2:
expre = Expression.Equal(prop, Expression.Constant(item.GetValue(this.entity1)));
whereExpression = Expression.Or(whereExpression, expre);
break;
case 3:
expre = Expression.Call(prop, method, Expression.Constant(GetVlaue(item.Name)));
whereExpression = Expression.And(whereExpression, expre);
break;
case 4:
expre = Expression.Call(prop, method, Expression.Constant(GetVlaue(item.Name)));
whereExpression = Expression.Or(whereExpression, expre);
break;
}
}
return Expression.Lambda<Func<TEntity, bool>>(whereExpression, para);
}
public Expression In( string filed, string[] objects) {
var prop = Expression.Property(para,filed);
var contains = typeof(Enumerable).GetMethods().FirstOrDefault(p => p.GetParameters().Length == 2 && p.Name == "Contains").MakeGenericMethod(typeof(string));
var call = Expression.Call(null, contains,Expression.Constant(objects), prop);
return call;
}
}
数据测试
Student stu = new Student() { id = "15", name = "s" };//x=>x.id=="15"&&x.name.Contains("s")
ExpressionBuilder<Student> eb = new ExpressionBuilder<Student>(stu);
Console.WriteLine(eb.Catchall());
//eb.And(eb.In("id", "17,15".Split(',')));
//var lamada = eb.CreateLamada();
//Console.WriteLine(lamada);
var list = stus.AsQueryable().Where(eb.Catchall()).ToList();
Console.WriteLine("筛选之前的数据");
foreach (var item in stus)
{
Console.WriteLine(item.id + " " + item.name);
}
Console.WriteLine("筛选之后的数据");
foreach (var item in list)
{
Console.WriteLine(item.id + " " + item.name);
}
结果如图
用表达式树构建的In:p=>"15,17".Split(",").Contains(p.id)
Student stu = new Student() { id = "15", name = "s" };//x=>x.id=="15"&&x.name.Contains("s")
ExpressionBuilder<Student> eb = new ExpressionBuilder<Student>(stu);
Console.WriteLine(eb.Catchall());
eb.And(eb.In("id", "17,15".Split(',')));
var lamada = eb.CreateLamada();
var list = stus.AsQueryable().Where(lamada).ToList();
结果如图
最后:如有不足请多指教