8,494
社区成员




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();
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));
}
}
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));
}
}
throw new NotImplementedException("string、IEnumerable以外类型的Contains表达式未实现!");
case ExpressComparison.Custom:
throw new NotImplementedException("暂无自定义实现");
}
return Expression.Empty();
}
}
public static Expression<Func<TEntity, bool>> GenerateExpressTree<TEntity>(this IMapFrom<TEntity> mapFrom) where TEntity : IBaseEntity, new()
{
var parameter = Expression.Parameter(typeof(TEntity), "__q");
var queryFieldsExpression = (from x in mapFrom.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(mapFrom)
}
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 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;
}
}
//测试
internal class VmTest : IMapFrom<TestCollection>
{
[ViewModelLabel(ExpressComparison.Contains)]
public string Tags { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
[TestMethod]
public async Task UseViewModelQuery()
{
var vm = new VmTest{Tags = "Tag99"};
var expr = vm.GenerateExpressTree();
var exprResult = RepositoryUnitTest.CreateRepository<TestCollection>().SearchFor(expr);
var list = await exprResult.ToListAsync();
Assert.IsTrue(list.Count >= 0);
}
Imports System.Linq.Expressions
Imports System.Linq
Imports System.Collections.Generic
Class A
Public Property Name As String
Public Property ID As Integer
Public Overrides Function ToString() As String
Return ID & "," & Name
End Function
End Class
Module Module1
Function MyWhere(Of T)(ByVal data As IQueryable(Of T), ByVal propname As String, ByVal value As Object) As IQueryable(Of T)
Dim param = Expression.Parameter(GetType(T), "x")
Dim body = Expression.Equal(Expression.MakeMemberAccess(param, GetType(T).GetProperty(propname)), Expression.Constant(value))
Dim lambdaexpr As Object = Expression.Lambda(body, param)
Return data.Where(CType(lambdaexpr, Expression(Of Func(Of T, Boolean))))
End Function
Sub Main()
Dim list As New List(Of A)
list.Add(New A() With {.ID = 1, .Name = "a"})
list.Add(New A() With {.ID = 2, .Name = "b"})
list.Add(New A() With {.ID = 3, .Name = "c"})
Console.WriteLine(MyWhere(list.AsQueryable(), "Name", "a").First())
Console.WriteLine(MyWhere(list.AsQueryable(), "ID", 2).First())
End Sub
End Module
Imports System.Linq.Expressions
Imports System.Linq
Imports System.Collections.Generic
Class A
Public Property Name As String
Public Property ID As Integer
Public Overrides Function ToString() As String
Return ID & "," & Name
End Function
End Class
Module Module1
Function MyWhere(Of T)(ByVal data As IEnumerable(Of T), ByVal propname As String, ByVal value As Object) As IEnumerable(Of T)
Dim param = Expression.Parameter(GetType(T), "x")
Dim body = Expression.Equal(Expression.MakeMemberAccess(param, GetType(T).GetProperty(propname)), Expression.Constant(value))
Dim lambdaexpr As Object = Expression.Lambda(body, param).Compile()
Return data.Where(CType(lambdaexpr, Func(Of T, Boolean)))
End Function
Sub Main()
Dim list As New List(Of A)
list.Add(New A() With {.ID = 1, .Name = "a"})
list.Add(New A() With {.ID = 2, .Name = "b"})
list.Add(New A() With {.ID = 3, .Name = "c"})
Console.WriteLine(MyWhere(list, "Name", "a").First())
Console.WriteLine(MyWhere(list, "ID", 2).First())
End Sub
End Module