C# 使用contains方法为列表为int的枚举属性生成LINQ Lambda表达式
我已经建立了一些扩展方法,用于使用IQueryable对泛型对象进行排序和过滤,以从中获取数据,到目前为止,它对所有类型都很有效,但对于枚举,我不知道如何解决这个问题,所以这里有一些示例C# 使用contains方法为列表为int的枚举属性生成LINQ Lambda表达式,c#,linq,lambda,enums,expression,C#,Linq,Lambda,Enums,Expression,我已经建立了一些扩展方法,用于使用IQueryable对泛型对象进行排序和过滤,以从中获取数据,到目前为止,它对所有类型都很有效,但对于枚举,我不知道如何解决这个问题,所以这里有一些示例 public enum ClaimStatusEnum { None = 0, Open = 10, Submitted = 20, Rejected = 30, Refunded = 40, Closed = 50, Received = 60,
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 };
现在,本例中的goel是在Claim表中找到的,在该表中,我们有带有枚举值的记录,这些记录在int的arr中
所以我想构建一个lambda表达式,它应该是泛型的,而不是硬编码类的类型,因为它可以是任何实体,也应该适用于任何给定的枚举
这是我目前使用的完全相同的东西,但唯一的区别是它适用于int而不是enum的属性,所以它对int类型非常有效,但是当涉及到enum类型时,我得到了一个错误
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);
这里有人能帮我如何使枚举类型工作吗?我已经尝试了很多不同的方法,它们都会出错
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;
}
但是,它应该适用于我想要的任何实体,这就是为什么它是通用的。我认为您需要这样做:
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);
1) 你犯了什么错误?2)
.MakeGenericMethod(typeof(int))
->.MakeGenericMethod(typeof(ClaimStatusEnum))
?我不能做typeof(ClaimStatusEnum),因为它可以是任何给定的枚举,它必须是generic。您能添加预期的用法吗?此外,您还可以始终为枚举类型添加泛型类型参数。我使用example.System.invalidoOperationException更新了该问题:“NavigationExpandingExpressionVisitor”对LINQ表达式“AsQueryable((IEnumerable)int[]{0,20,})”的处理失败。这可能表明EF核心中存在缺陷或限制。有关更多详细信息,请参阅。在Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCallExpression(MethodCallExpression MethodCallExpression)中,代码片段也有一些拼写错误,下面是我使用的。call=Expression.call(mi,castarrteonum,m);另外还有一个额外的)at Expression.Constant(arr)@SolStein更改了调用=
部分。您的异常非常奇怪,因为我没有将arr
转换为IEnumerable
,我的代码应该生成arr.cast()
我想这行正在执行var castMi=typeof(Enumerable).GetMethod(“cast”)@SolStein还可以尝试另一种方法—将属性强制转换为int
-表达式。转换(m,typeof(int))
并将其传递给调用,而不是m
。