2015-05-16 16 views
6

Tôi nhận được ngoại lệ này khi tôi chạy mã này.Gọi hàm Lambda động

ParameterExpression loại System.Int64 không thể được sử dụng cho tham số đại biểu của loại System.Object

Tôi biết nó là cái gì để làm với Expression.Lambda<func<object,bool>> một phần của mã. Nói chung, tôi muốn vượt qua bất kỳ loại ParameterExpression vào phương pháp này và nó sẽ gọi biểu thức.

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); 
} 

EDIT: tôi đã thấy câu trả lời này cho một câu hỏi tương tự

Expression of type 'System.Int32' cannot be used for return type 'System.Object' Tôi không biết làm thế nào để áp dụng nó vào mã của tôi mặc dù

EDIT 2: Các vấn đề chính là dòng Expression.Lambda<Func<object, bool>>(conversion, new ParameterExpression[] { paramExpression })); này đang cho tôi một ngoại lệ. paramExpression chứa Int64 nhưng nó là một đối tượng. Tôi không biết làm thế nào để tự động nói với Func từ thông tin tôi đã có hoặc nếu điều đó là có thể.

MỤC TIÊU: Tôi cố gắng để làm một cái gì đó như thế này data.OrderBy(x=>x.DynamicProperty);

+0

Bạn đang sử dụng T và tham số của bạn là một struct ... bạn không thể đúc một struct để phản đối –

+0

Bạn có thể gửi một ví dụ về cách bạn đang sử dụng này, vì nó đứng ngay hiện nay? Nếu không có thì thật khó để đánh giá cách khắc phục nó. –

+0

Tôi đã đăng phương thức gọi hai phương thức còn lại. Không có gì cao hơn bây giờ chỉ vì nó không hoạt động được nêu ra. Dữ liệu 'IQueryable ' sẽ giống như thế này 'Danh sách dữ liệu' @EBrown – imGreg

Trả lời

3

Đây là những gì bạn yêu cầu, tôi nghĩ ... Tôi đã thử nghiệm nó và nó dường như làm việc.

// 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; 
} 

Vui lòng không bao giờ sử dụng AsQueryable<>(). Nó không làm những gì bạn nghĩ, và nó là hoàn toàn vô dụng bên ngoài thử nghiệm đơn vị và trường hợp sử dụng rất cụ thể.

+0

Đây là chính xác những gì tôi muốn. Tôi không nhận ra nó phức tạp như thế nào. – imGreg

+0

Ngoài ra, nó sẽ là tốt đẹp nếu bạn sẽ đăng thông tin đó sẽ giải thích lý do tại sao điều này hoạt động trên khác. –

+0

@EBrown Đã nhận xét mọi thứ. – xanatos

0

Bạn có thể sử dụng tiện ích OrderByString của mình. https://www.nuget.org/packages/OrderByString/ Phải mất chuỗi cho các tham số sắp xếp. Các chuỗi tham số sắp xếp có thể là danh sách các tên thuộc tính được phân tách bằng dấu phẩy, chẳng hạn như "Prop1, Prop2" hoặc nó có thể bao gồm thứ tự sắp xếp như trong "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; 
} 

HOẶC

Bạn có thể sử dụng các phương pháp sau đây GetExpressionForProperty trả về biểu thức loại dự kiến ​​cho OrderBy, OrderByDescending, ThenBy, hoặc 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); 
} 
Các vấn đề liên quan