2015-05-16 114 views
6

我在運行此代碼時遇到此異常。 System.Int64動態Lambda表達式調用

ParameterExpression不能被用於類型System.Object

的委託參數,我知道這件事情做的代碼Expression.Lambda<func<object,bool>>一部分。總的來說,我想通過任何類型的​​到這個方法,它會調用表達式。

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

您使用的是T <對象,布爾>和您的參數是一個結構......你可以不投的結構來反對 –

+0

你能後的你是如何使用這樣的一個例子,因爲它代表權現在?沒有這一點,很難評估如何解決它。 –

+0

我貼的方法調用了另外兩種方法。沒有什麼比現在更高,只是因爲它還沒有工作。 'IQueryable data'就是這樣'List data' @EBrown – imGreg

回答

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<>()。它不會做你的想法,在單元測試和非常具體的用例之外是完全沒用的。

+0

這正是我想要的。我不知道它有多複雜。 – imGreg

+0

此外,如果您發佈的信息可以解釋爲什麼這可以在另一個上工作,那將會很好。 –

+0

@EBrown評論一切。 – xanatos

0

您可以使用我的OrderByString擴展名。 https://www.nuget.org/packages/OrderByString/它需要字符串作爲排序參數。排序參數字符串可以是屬性名稱的逗號分隔列表,例如「Prop1,Prop2」,或者可以包含排序順序,如「Prop1 DESC,Prop2 ASC」中的排序順序。

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方法返回排序依據,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); 
}