Linq:Queryable.OrderBy()使用表达式集合

Zol*_*yak 8 c# linq lambda entity-framework

我想知道如何在列表中存储orderby表达式.这就是我想写的:

List<Expression<Func<Products,Object>>> list = new List<Expression<Func<Products,Object>>>()
{
  p => p.Name,
  p => p.Id
};
Run Code Online (Sandbox Code Playgroud)

然后:

var expr = list[0];
myProducts.OrderBy( expr );
Run Code Online (Sandbox Code Playgroud)

该工程p.Name,但不工作p.Id(list[1]),因为它降低follwing例外

EntityFramework.SqlServer.dll中出现未处理的"System.NotSupportedException"类型异常附加信息:无法将类型"System.Int32"强制转换为"System.Object"类型.LINQ to Entities仅支持转换EDM原语或枚举类型.

我必须使用什么类型的列表?

hai*_*770 1

这是我的解决方案(使用 Reflection 并基于DynamicLinq思想):

定义一个ConvertableExpression类,以便我们可以拦截对自定义的调用OrderBy()

public class ConvertableExpression<T>
{
    public ConvertableExpression(Expression<Func<T, object>> expr)
    {
        this.Expression = expr;
    }

    public Expression<Func<T, object>> Expression { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)

引入扩展方法以更轻松地从正常进行转换Expression

public static class ExpressionExtensions
{
    public static ConvertableExpression<T> AsConvertable<T>(this Expression<Func<T, object>> expr)
    {
        return new ConvertableExpression<T>(expr);
    }
}
Run Code Online (Sandbox Code Playgroud)

IQueryable通过基于反射的实现进行扩展OrderBy()

public static class QueryableExtensions
{
    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, ConvertableExpression<T> expr)
    {
        Expression queryExpr = source.Expression;

        var exprBody = SkipConverts(expr.Expression.Body);
        var lambda = Expression.Lambda(exprBody, expr.Expression.Parameters);
        var quote = Expression.Quote(lambda);

        queryExpr = Expression.Call(typeof(Queryable), "OrderBy", new[] { source.ElementType, exprBody.Type }, queryExpr, quote);

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

    private static Expression SkipConverts(Expression expression)
    {
        Expression result = expression;

        while (result.NodeType == ExpressionType.Convert || result.NodeType == ExpressionType.ConvertChecked)
            result = ((UnaryExpression)result).Operand;

        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

myProducts.OrderBy(expr.AsConvertable());
Run Code Online (Sandbox Code Playgroud)