使用包含枚举 属性 的方法和 int 列表构建 LINQ Lambda 表达式
Build LINQ Lambda Expression with contains method for enum property with list of int
我已经构建了一些扩展方法,用于使用 IQueryable 从中获取数据来排序和过滤通用对象,到目前为止它适用于所有类型,但对于枚举,我不知道如何解决这个问题,所以这是一些例子。
public enum ClaimStatusEnum
{
None = 0,
Open = 10,
Submitted = 20,
Rejected = 30,
Refunded = 40,
Closed = 50,
Received = 60,
Backorder = 70,
UnderReview = 80
}
请注意!这只是枚举的一个例子,但我在执行时不知道枚举类型是什么,所以请注意我必须使用通用类型。
现在这里有一个示例,其中包含一个 属性,其中包含该枚举类型。
public class Claim
{
[Key]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public ClaimStatusEnum ClaimStatus { get; set; }
}
现在这里是一个过滤器的例子,它与枚举中的 int 值列表一起传递。
var arr = new int[] { 20, 30, 40 };
现在这个例子中的目标是在 Claim table 中找到我们在 int 的 arr 中具有枚举值的记录。
所以我想构建一个 lambda 表达式,它应该是通用的而不是对 类 的类型进行硬编码,因为它可以是任何实体并且也应该适用于任何给定的枚举。
所以这是我目前用于完全相同的东西,但唯一的区别是它用于 属性,它是一个 int 而不是一个枚举,所以它适用于 int 类型,但是当关于枚举类型,我得到一个错误。
ConstantExpression c = Expression.Constant(arr);
MethodInfo mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
call = Expression.Call(mi, c, m);
谁能帮我解决枚举类型的问题?我已经尝试了很多不同的方法,他们都抛出错误。
下面是如何将其用作扩展方法。
public static IQueryable<T> EntitySortAndFilter<T>(this IQueryable<T> data, PageFilter filter, T type)
{
foreach (var item in filter.Filter.Filters)
{
if (item.Value == null || item.Condition == null || item.Field == null)
continue;
ParameterExpression e;
Expression m, call;
PropertyInfo prop;
prop = type.GetType().GetProperty(item.Field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
e = Expression.Parameter(type.GetType(), "e");
m = Expression.MakeMemberAccess(e, prop );
var arr = item.Value;
ConstantExpression c = Expression.Constant(arr);
MethodInfo mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
call = Expression.Call(mi, c, m);
var lambda = Expression.Lambda<Func<T, bool>>(call, e);
data = data.Where(lambda);
}
return data;
}
在调用这个扩展时,我是这样调用的。
var example = query.EntitySortAndFilter(filter, new Claim());
但同样,它应该适用于我想要的任何实体,这就是为什么它是通用的。
我认为你需要做这样的事情:
if(prop.PropertyType.IsEnum) // if property is enum
{
// create expression to cast array values to enum
var castMi = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(prop.PropertyType);
var castArrToEnum = Expression.Call(castMi, Expression.Constant(arr)));
// make contains for needed type
mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(prop.PropertyType);
call = Expression.Call(mi, castArrToEnum, m);
}
如果这不起作用,您可以随时尝试其他方法:
var mc = Expression.Convert(m, typeof(int));
ConstantExpression c = Expression.Constant(arr);
MethodInfo mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
call = Expression.Call(mi, c, mc);
我已经构建了一些扩展方法,用于使用 IQueryable 从中获取数据来排序和过滤通用对象,到目前为止它适用于所有类型,但对于枚举,我不知道如何解决这个问题,所以这是一些例子。
public enum ClaimStatusEnum
{
None = 0,
Open = 10,
Submitted = 20,
Rejected = 30,
Refunded = 40,
Closed = 50,
Received = 60,
Backorder = 70,
UnderReview = 80
}
请注意!这只是枚举的一个例子,但我在执行时不知道枚举类型是什么,所以请注意我必须使用通用类型。
现在这里有一个示例,其中包含一个 属性,其中包含该枚举类型。
public class Claim
{
[Key]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public ClaimStatusEnum ClaimStatus { get; set; }
}
现在这里是一个过滤器的例子,它与枚举中的 int 值列表一起传递。
var arr = new int[] { 20, 30, 40 };
现在这个例子中的目标是在 Claim table 中找到我们在 int 的 arr 中具有枚举值的记录。
所以我想构建一个 lambda 表达式,它应该是通用的而不是对 类 的类型进行硬编码,因为它可以是任何实体并且也应该适用于任何给定的枚举。
所以这是我目前用于完全相同的东西,但唯一的区别是它用于 属性,它是一个 int 而不是一个枚举,所以它适用于 int 类型,但是当关于枚举类型,我得到一个错误。
ConstantExpression c = Expression.Constant(arr);
MethodInfo mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
call = Expression.Call(mi, c, m);
谁能帮我解决枚举类型的问题?我已经尝试了很多不同的方法,他们都抛出错误。
下面是如何将其用作扩展方法。
public static IQueryable<T> EntitySortAndFilter<T>(this IQueryable<T> data, PageFilter filter, T type)
{
foreach (var item in filter.Filter.Filters)
{
if (item.Value == null || item.Condition == null || item.Field == null)
continue;
ParameterExpression e;
Expression m, call;
PropertyInfo prop;
prop = type.GetType().GetProperty(item.Field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
e = Expression.Parameter(type.GetType(), "e");
m = Expression.MakeMemberAccess(e, prop );
var arr = item.Value;
ConstantExpression c = Expression.Constant(arr);
MethodInfo mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
call = Expression.Call(mi, c, m);
var lambda = Expression.Lambda<Func<T, bool>>(call, e);
data = data.Where(lambda);
}
return data;
}
在调用这个扩展时,我是这样调用的。
var example = query.EntitySortAndFilter(filter, new Claim());
但同样,它应该适用于我想要的任何实体,这就是为什么它是通用的。
我认为你需要做这样的事情:
if(prop.PropertyType.IsEnum) // if property is enum
{
// create expression to cast array values to enum
var castMi = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(prop.PropertyType);
var castArrToEnum = Expression.Call(castMi, Expression.Constant(arr)));
// make contains for needed type
mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(prop.PropertyType);
call = Expression.Call(mi, castArrToEnum, m);
}
如果这不起作用,您可以随时尝试其他方法:
var mc = Expression.Convert(m, typeof(int));
ConstantExpression c = Expression.Constant(arr);
MethodInfo mi = typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Contains")
.Single(m => m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(int));
call = Expression.Call(mi, c, mc);