【问题标题】:How To Create An OrderBy Expression Tree For Run Time Sorting?如何为运行时排序创建 OrderBy 表达式树?
【发布时间】:2019-08-26 23:58:14
【问题描述】:

我正在尝试为这个表达式创建一个表达式树 Table.OrderBy(x => Math.Abs​​(x.Temperature - temp)) 得到最接近的温度值

我有一个已经按属性排序的扩展方法,但是我不确定如何插入 Math.Abs​​ 表达式。

  public IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder)
    {
        var type = typeof(T);
        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[] { type, property.PropertyType };
        var methodName = sortOrder == ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
        var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));

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

编辑:

这是我找到的解决方案。感谢您的帮助!

    /// <summary>
    /// Gets the TEntity value closest to the given property value
    /// </summary>
    /// <param name="property">Property name</param>
    /// <param name="value">Property value</param>
    /// <returns></returns>
    public TEntity GetNearestEntity(string property, double value)
    {
        //Error handling, if property doesn't have a double value type
        if (typeof(TEntity).GetProperty(property).PropertyType != typeof(double)) return null;

        //Parameter in lambda
        ParameterExpression param = Expression.Parameter(typeof(TEntity), "x");

        //Create member property [ property == ...]
        MemberExpression member = Expression.Property(param, typeof(TEntity).GetProperty(property));

        //Create constant expression [ ... == value]
        ConstantExpression constExp = Expression.Constant(value);

        //Binary expression [param.property - value]
        BinaryExpression binaryExp = Expression.Subtract(member, constExp);

        //Gets method info for Math.Abs
        MethodInfo method = typeof(Math).GetMethod("Abs", new[] { binaryExp.Type });

        //Creates method Math.Abs(x.Property - value)
        var absCallExpression = Expression.Call(null, method, binaryExp);

        //Create lambda
        Expression<Func<TEntity, double>> lambda = Expression.Lambda<Func<TEntity, double>>(absCallExpression, new ParameterExpression[] { param });

        //Gets single entity from DbSet
        TEntity entity = _entity.OrderBy(lambda).FirstOrDefault();

        return entity;
    }

【问题讨论】:

    标签: c# linq lambda


    【解决方案1】:

    您应该在propertyAccess 上执行此操作(顺便说一句,您的代码示例看起来不完整,因为我没有看到减法表达式):

    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var absMethodInfo = typeof(Math).GetMethod("Abs", new[]{propertyAccess.Type});
    var absCallExpression = Expression.Call(null, absMethodInfo, propertyAccess);
    var orderByExp = Expression.Lambda(absCallExpression, parameter);
    // ...
    

    想法是搜索Math.Abs方法(通过断言absMethodInfo不为空来确保搜索成功)并在属性访问(Expression.MakeMemberAccess(parameter, property))上生成方法调用表达式-常量表达式(这部分您的代码示例中缺少)。希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-01
      • 2014-03-19
      • 1970-01-01
      • 1970-01-01
      • 2016-04-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多