为动态对象创建linq表达式树

时间:2016-05-27 19:18:10

标签: c# linq dynamic lambda expression-trees

我正在尝试动态构建表达式树以进行排序。排序将在我的web api的动作过滤器中进行。因此,在运行时之前,对象的类型将是未知的。

以下是概述:
在操作过滤器级别:

IEnumerable<object> model = null;
context.Response.TryGetContentValue(out model);
model=model.OrderByExtension(orderByField, orderDirection);
context.Response.Content=new ObjectContent<IEnumerable<object>>(model, new JsonMediaTypeFormatter());

和扩展方法:

 public static IQueryable<T> OrderByExtension<T>(this IQueryable<T> source, string sortProperty, Sorting.SortingOption sortOrder)
        {
            var type = source.FirstOrDefault().GetType(); //Gets the type of object passed, since typeof(T) is only object at this point
            var property = type.GetProperty(sortProperty);
            var parameter = Expression.Parameter(type, "p");
            var propertyAccess = Expression.MakeMemberAccess(parameter, property);
            var orderByExp = Expression.Lambda(propertyAccess, parameter);
            var typeArguments = new Type[] { typeof(T), property.PropertyType };
            var methodName = sortOrder == Sorting.SortingOption.Asc ? "OrderBy" : "OrderByDescending";
            var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));

            return source.Provider.CreateQuery<T>(resultExp);
        }

在Expression.Call上 - 我收到错误:没有通用方法&#39; OrderByDescending&#39; on type&#39; System.Linq.Queryable&#39;与提供的类型参数和参数兼容。

我假设类型&#39;对象&#39;之间存在不匹配。和调用OrderBy方法时的实际类型。

无论如何要让它发挥作用吗?

提前致谢。 ps:我还尝试通过.MakeGenericMethod为OrderBy创建一个通用方法 - 但没有成功。

1 个答案:

答案 0 :(得分:0)

问题是您正在生成实际基础类型的函数的表达式,而不是源表达式的类型(object)。您需要在生成的表达式中为您的类型添加转换。

public static IQueryable<object> OrderByExtension(this IQueryable<object> source, string sortProperty, SortOrder sortOrder = SortOrder.Unspecified)
{
    var sourceType = typeof(object);
    var underlyingType = source.First().GetType();
    var propertyType = underlyingType.GetProperty(sortProperty).PropertyType;
    var param = Expression.Parameter(sourceType);
    var body = Expression.Property(
        Expression.Convert(param, underlyingType), sortProperty
    );
    var lambda = Expression.Lambda(body, param);

    var sortMethod = sortOrder == SortOrder.Descending ? "OrderByDescending" : "OrderBy";
    var expr = Expression.Call(typeof(Queryable), sortMethod, new Type[] { sourceType, propertyType },
        source.Expression, lambda
    );
    return source.Provider.CreateQuery<object>(expr);
}