运行此代码时,我收到此异常。
System.Int64
类型的ParameterExpression不能用于System.Object
类型的委托参数
我知道这与代码的Expression.Lambda<func<object,bool>>
部分有关。总的来说,我希望将任何类型的ParameterExpression
传递给此方法,它将调用表达式。
public static IQueryable<T> OrderData<T>(IQueryable<T> data)
{
try
{
Order order = Order.ASC;
var result = Enum.TryParse<Order>(_gridSettings.SortOrder, true, out order);
if (_gridSettings.IsSearch)
{
data = ExpressionSort(order, data, typeof(T).GetProperty(_gridSettings.SortColumn));
}
else
{
data = ExpressionSort(order, data, _defaultColumn);
}
}
catch (Exception ex)
{
log.WriteLog(MethodBase.GetCurrentMethod(), LogLevel.FATAL, ex);
}
return data;
}
private static IQueryable<T> ExpressionSort<T>(Order order, IQueryable<T> data, PropertyInfo property)
{
// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression paramExpression = Expression.Parameter(property.PropertyType, property.Name);
IQueryable<T> queryableData = data.AsQueryable<T>();
switch (order)
{
case Order.ASC:
return ExecuteCall(paramExpression, paramExpression, queryableData, "OrderBy");
case Order.DESC:
return ExecuteCall(paramExpression, paramExpression, queryableData, "OrderByDescending");
}
return data;
}
private static IQueryable<T> ExecuteCall<T>(Expression expression, ParameterExpression paramExpression, IQueryable<T> queryableData, string linqMethod)
{
MethodCallExpression callExpression = Expression.Call(
typeof(Queryable),
linqMethod,
new Type[] { queryableData.ElementType },
queryableData.Expression,
Expression.Lambda<Func<object, bool>>(expression, new ParameterExpression[] { paramExpression }));
// Create an executable query from the expression tree.
return queryableData.Provider.CreateQuery<T>(callExpression);
}
修改 我确实看到了类似问题的答案
Expression of type 'System.Int32' cannot be used for return type 'System.Object' 我不知道如何将它应用于我的代码
编辑2:
主要问题是这条Expression.Lambda<Func<object, bool>>(conversion, new ParameterExpression[] { paramExpression }));
行给了我一个例外。 paramExpression包含一个Int64但它期望一个对象。我不知道如何动态告诉Func我已经拥有的信息或者是否可能。
目标:
我正在尝试做这样的事情data.OrderBy(x=>x.DynamicProperty);
答案 0 :(得分:3)
这就是你要求的,我想......我已经测试了它,它似乎有效。
// Caching of the reflection
private static readonly MethodInfo orderByMethod = GetOrderByMethod("OrderBy");
private static readonly MethodInfo orderByDescendingMethod = GetOrderByMethod("OrderByDescending");
private static IOrderedQueryable<TSource> ExpressionSort<TSource>(Order order, IQueryable<TSource> source, PropertyInfo property)
{
// Compose the expression tree that represents the parameter to
// the predicate.
// The expression you would use is source => source.Property,
// The parameter of the lambda, source
ParameterExpression sourceExpression = Expression.Parameter(typeof(TSource), "source");
// Accessing the expression
MemberExpression propertyExpression = Expression.Property(sourceExpression, property);
// The full lambda expression. We don't need the
// Expression.Lambda<>, but still the keySelector will be an
// Expression<Func<,>>, because Expression.Lambda does it
// authomatically. LambdaExpression is simply a superclass of
// all the Expression<Delegate>
LambdaExpression keySelector = Expression.Lambda(propertyExpression, sourceExpression);
// The OrderBy method we will be using, that we have cached
// in some static fields
MethodInfo method = order == Order.ASC ? orderByMethod : orderByDescendingMethod;
// Adapted from Queryable.OrderBy (retrieved from the reference
// source code), simply changed the way the OrderBy method is
// retrieved to "method"
return (IOrderedQueryable<TSource>)source.Provider.CreateQuery<TSource>(Expression.Call(null, method.MakeGenericMethod(new Type[]
{
typeof(TSource),
property.PropertyType
}), new Expression[]
{
source.Expression,
Expression.Quote(keySelector)
}));
}
private static MethodInfo GetOrderByMethod(string methodName)
{
// Here I'm taking the long and more correct way to find OrderBy/
// OrderByDescending: looking for a public static method with the
// right name, with two generic arguments and that has the
// parameters related to those two generic arguments in a certain
// way (they must be IQueryable<arg0> and Expression<Func<arg0,
// arg1>>
MethodInfo orderByMethod = (from x in typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
where x.Name == methodName
let generics = x.GetGenericArguments()
where generics.Length == 2
let parameters = x.GetParameters()
where parameters.Length == 2 &&
parameters[0].ParameterType == typeof(IQueryable<>).MakeGenericType(generics[0]) &&
parameters[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(generics))
select x).Single();
return orderByMethod;
}
请不要使用AsQueryable<>()
。它不符合您的想法,在单元测试和非常具体的用例之外完全没用。
答案 1 :(得分:1)
您可以使用我的OrderByString扩展名。 https://www.nuget.org/packages/OrderByString/它需要排序参数的字符串。排序参数字符串可以是以逗号分隔的属性名称列表,例如&#34; Prop1,Prop2和#34;或者它可以包括排序顺序,如&#34; Prop1 DESC,Prop2 ASC&#34;。
using OrderByExtensions;
public static IQueryable<T> OrderData<T>(IQueryable<T> data)
{
try
{
Order order = Order.ASC;
var result = Enum.TryParse<Order>(_gridSettings.SortOrder, true, out order);
var sortColumn = _gridSettings.IsSearch ? _gridSettings.SortColumn : _defaultColumn;
data = data.OrderBy(sortColumn + " " + _gridSettings.SortOrder.ToString());
}
catch (Exception ex)
{
log.WriteLog(MethodBase.GetCurrentMethod(), LogLevel.FATAL, ex);
}
return data;
}
OR
您可以使用以下GetExpressionForProperty方法返回OrderBy,OrderByDescending,ThenBy或ThenByDescending的预期排序表达式。
private static IQueryable<T> ExpressionSort<T>(Order order, IQueryable<T> data, PropertyInfo property)
{
Expression<Func<T, object>> propertyExpression = GetExpressionForProperty<T>(property);
return order == Order.DESC ? data.OrderByDescending(propertyExpression) : data.OrderBy(propertyExpression);
}
static Expression<Func<TSource, object>> GetExpressionForProperty<TSource>(PropertyInfo propertyInfo)
{
var param = Expression.Parameter(typeof(TSource));
return Expression.Lambda<Func<TSource, object>>(
Expression.Convert(
Expression.Property(param, propertyInfo),
typeof(object)
)
, param);
}
答案 2 :(得分:0)
尝试使用Expression.Convert。这是一个类似的问题,可以为您提供更多指导:
Expression of type 'System.Int32' cannot be used for return type 'System.Object'