我尝试使用lambda表达式作为通过反射调用IEnumerable.Where的谓词。
e.Query的类型为System.Data.Objects.ObjectQuery<T>
,其中T在运行时已知。 ObjectQuery实现IEnumerable。
//the current element type
Type currentType = e.Query.ElementType;
ParameterExpression typeParameterExpression = Expression.Parameter(currentType);
ConstantExpression propertyConstantExpression = Expression.Constant(GameId, GameId.GetType());
BinaryExpression equalityExpression = Expression.Equal(Expression.PropertyOrField(typeParameterExpression, "GameId"), propertyConstantExpression);
Type genericFunc = typeof(Func<,>).MakeGenericType(currentType, typeof(bool)); //genericFunc = {Name = "Func`2" FullName = "System.Func`2[[OfferManagementBackOffice.Placement, OfferManagementBackOffice, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}
Expression predicateExpression = Expression.Lambda(genericFunc, equalityExpression, typeParameterExpression); //predicateExpression = {Param_0 => (Param_0.GameId == 2)}
var whereMethods = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Where");
MethodInfo whereMethod = null;
foreach (var methodInfo in whereMethods)
{
var paramType = methodInfo.GetParameters()[1].ParameterType;
if (paramType.GetGenericArguments().Count() == 2)
{
// we are looking for Func<TSource, bool>, the other has 3
whereMethod = methodInfo;
}
}
whereMethod = whereMethod.MakeGenericMethod(currentType);
//whereMethod = {System.Collections.Generic.IEnumerable`1[OfferManagementBackOffice.Placement] Where[Placement](System.Collections.Generic.IEnumerable`1[OfferManagementBackOffice.Placement], System.Func`2[OfferManagementBackOffice.Placement,System.Boolean])}
var result = whereMethod.Invoke(e.Query, new object[] { e.Query, predicateExpression });
当我在whereMethod上尝试Invoke()时,我收到此错误:
错误:类型的对象
'System.Linq.Expressions.Expression``1[System.Func``2[OfferManagementBackOffice.Placement,System.Boolean]]'
无法转换为类型'System.Func``2[OfferManagementBackOffice.Placement,System.Boolean]'
。
我在上面尝试实现的目标是(此处为T = Placement),但适用于任何类型。
Expression<Func<Placement, bool>> lambda1 = Expression.Lambda<Func<Placement, bool>>(equalityExpression, typeParameterExpression);
e.Query.Cast<Placement>().Where(lambda1);
答案 0 :(得分:0)
首先,我要感谢@Grundy花时间帮助我找到解决方案:
为了使Where调用工作,我必须.Compile()lambda表达式
var predicateExpression = Expression.Lambda(genericFunc, equalityExpression, typeParameterExpression).Compile();
可行,但它返回WhereEnumerableIterator<T>
而不是所需的ObjectQuery。
事实证明我需要使用Queryable.Where而不是Enumerable.Where。但是现在,由于一些奇怪的原因,我不需要(实际上我不能)Compile()lambda表达式使它工作。这是最终的工作代码:
short GameId = Convert.ToInt16(Session["GlobalGameFilter"]);
Type currentType = e.Query.ElementType;
ParameterExpression typeParameterExpression = Expression.Parameter(currentType);
ConstantExpression propertyConstantExpression = Expression.Constant(GameId, GameId.GetType());
BinaryExpression equalityExpression = Expression.Equal(Expression.PropertyOrField(typeParameterExpression, "GameId"), propertyConstantExpression);
Type genericFunc = typeof(Func<,>).MakeGenericType(currentType, typeof(bool));
var predicateExpression = Expression.Lambda(genericFunc, equalityExpression, typeParameterExpression);
var whereMethods = typeof(System.Linq.Queryable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(mi => mi.Name == "Where");
MethodInfo whereMethod = whereMethods.ElementAt(0).MakeGenericMethod(currentType);
var result = whereMethod.Invoke(e.Query, new object[] { e.Query, predicateExpression });
e.Query = (IQueryable)result;
现在结果是ObjectQuery类型,这正是我需要的。