110,535
社区成员
发帖
与我相关
我的任务
分享
a => a.tdIsDelete != true && a.uStatus >= 0 && ((a.uLoginName != null && a.uLoginName.Contains(key)) || (a.uRealName != null && a.uRealName.Contains(key)))
a => a.tdIsDelete != true && a.uStatus >= 0 && ((a.uLoginName != null && a.uLoginName.Contains(key)))
public enum ExpressComparison
{
/// <summary>
/// 等于
/// </summary>
Equal,
/// <summary>
/// 包含
/// </summary>
Contains,
/// <summary>
/// 不等于
/// </summary>
NoEqual,
/// <summary>
/// 大于
/// </summary>
Gt,
/// <summary>
/// 小于
/// </summary>
Lt,
/// <summary>
/// 大于或等于
/// </summary>
GtOrEqual,
/// <summary>
/// 小于或等于
/// </summary>
LtOrEqual,
/// <summary>
/// 自定义规则
/// </summary>
Custom
}
[AttributeUsage(AttributeTargets.Property)]
public class ViewModelLabelAttribute:Attribute
{
public ExpressComparison Comparison { get; private set; }
/// <summary>
/// 生成表达式树,需要比较的方式
/// </summary>
/// <param name="expressComparison">比较方式</param>
public ViewModelLabelAttribute(ExpressComparison expressComparison)
{
Comparison = expressComparison;
}
}
定义比较的枚举和特性,然后是用反射和特性标注的方式来生成表达式树
public static class ExpressAction
{
internal class QueryField
{
public ViewModelLabelAttribute Label { get; set; }
public PropertyInfo Property { get; set; }
public object Value { get; set; }
internal Expression HandleField(ParameterExpression parameter)
{
if (Value == null) return Expression.Empty();
if (Property.PropertyType.IsEnum && Convert.ToInt32(Value) == -1)
return Expression.Empty();
var memberExpr = Expression.Property(parameter, Property);
switch (Label.Comparison)
{
case ExpressComparison.Equal:
return Expression.Equal(memberExpr, Expression.Constant(Value));
case ExpressComparison.Gt:
return Expression.GreaterThan(memberExpr, Expression.Constant(Value));
case ExpressComparison.GtOrEqual:
return Expression.GreaterThanOrEqual(memberExpr, Expression.Constant(Value));
case ExpressComparison.Lt:
return Expression.LessThan(memberExpr, Expression.Constant(Value));
case ExpressComparison.LtOrEqual:
return Expression.LessThanOrEqual(memberExpr, Expression.Constant(Value));
case ExpressComparison.NoEqual:
return Expression.NotEqual(memberExpr, Expression.Constant(Value));
case ExpressComparison.Contains:
if (Property.PropertyType == typeof(string) && Value is string)
{
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
if (containsMethod != null)
{
// return Expression.Call(memberExpr, containsMethod,
// Expression.Constant(Property.GetValue(null)), Expression.Constant(Value));
return Expression.Call(memberExpr, containsMethod, Expression.Constant(Value));
}
}
if (typeof(IEnumerable).IsAssignableFrom(Property.PropertyType))
{
var containsMethod = typeof(Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
.FirstOrDefault(x =>
x.Name == "Contains" && x.ReturnType == typeof(bool) &&
x.GetParameters().Length == 2);
if (containsMethod != null)
{
containsMethod = containsMethod.MakeGenericMethod(Value.GetType());
return Expression.Call(containsMethod, memberExpr,Expression.Constant(Value));
}
}
case ExpressComparison.Custom:
throw new NotImplementedException("暂无自定义实现");
//..... 其他实现
}
return Expression.Empty();
}
}
public static Expression<Func<TEntity, bool>> GenerateExpressTree<TEntity>(this TEntity entity) where TEntity : IBaseEntity, new()
{
var parameter = Expression.Parameter(typeof(TEntity), "__q");
var queryFieldsExpression = (from x in entity.GetType().GetProperties()
let attr = x.GetCustomAttribute<ViewModelLabelAttribute>()
where attr != null
let field = new QueryField
{
Label = attr,
Property = typeof(TEntity).GetProperty(x.Name),
Value = x.GetValue(entity)
}
select field.HandleField(parameter)).Where(x => x.NodeType != ExpressionType.Default).ToList();
var expression = (Expression)Expression.Constant(true);//(Expression)Expression.Equal(Expression.Constant(1), Expression.Constant(1));
foreach (var expr in queryFieldsExpression)
{
if (queryFieldsExpression.IndexOf(expr) == 0)
{
expression = expr;
continue;
}
expression = Expression.AndAlso(expression, expr);
}
return Expression.Lambda<Func<TEntity, bool>>(expression, parameter);
}
}
单元测试通过,你可以尝试一下
public class VmUser : IBaseEntity
{
//[ViewModelLabel(ExpressComparison.Equal)]
public string Id { get; set; }
[ViewModelLabel(ExpressComparison.Contains)]
public string Name { get; set; }
public string Avatar { get; set; }
[ViewModelLabel(ExpressComparison.GtOrEqual)]
public int Age { get; set; }
[ViewModelLabel(ExpressComparison.Contains)]
public string Groups { get; set; }
}
[TestMethod]
public void Lambda表达式树生成测试()
{
var viewModel = new VmUser
{
Avatar = "http://localhost:9527/images/laola.png",
Id = "dpangzi",
Name = "d",
Age = 30,
Groups = "666"
};
var list = new List<UserTest>
{
new UserTest
{
Avatar = "http://localhost:9527/images/laola.png",
Id = "dppangzi",
Name = "跳动de指尖",
Age = 30,
Groups = new[] {"111", "222", "333"}
},
new UserTest
{
Avatar = "http://localhost:9527/images/laola.png",
Id = "xxxxx",
Name = "yyyyy",
Age = 28,
Groups = new[] {"444", "555", "666"}
},
new UserTest
{
Avatar = "http://localhost:9527/images/laola.png",
Id = "zzzzz",
Name = "qqqqq",
Age = 18,
Groups = new[] {"777", "888", "999"}
}
};
var expr = viewModel.GenerateExpressTree();
var result = list.Where(expr.Compile()).ToList();
Assert.IsTrue(result.Count > 0);
}