我试图使用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上尝试调用()时,我得到了以下错误:
错误:无法将
'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);发布于 2015-09-02 13:38:51
首先,我要感谢@Grundy抽出时间来帮助我找到解决这个问题的方法:
为了使Where调用工作,我必须使用lambda表达式.Compile()
var predicateExpression = Expression.Lambda(genericFunc, equalityExpression, typeParameterExpression).Compile();这是可行的,但它返回一个WhereEnumerableIterator<T>而不是所需的ObjectQuery。
事实证明,我需要使用Queryable.Where而不是Enumerable.Where。但是现在,由于一些奇怪的原因,我不需要(实际上我不能)编译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类型,这正是我所需要的。
https://stackoverflow.com/questions/32353834
复制相似问题