动态创建排序Lambda表达式

本文关键字:表达式 Lambda 排序 创建 动态 | 更新日期: 2023-09-27 18:24:57

我想使用lambda表达式按照任意列/字段名对任意实体类型的IEnumerable进行排序。

我有这样的分类功能:

 public static IEnumerable<T> SortByFieldName<T>(IEnumerable<T> target, string sortPropertyName, string sortDirection)
    {
        if (!String.IsNullOrEmpty(sortPropertyName))
        {
            Expression<Func<T, object>> sortExpression = GetSortLambda<T>(sortPropertyName);
            switch (sortDirection.ToLower())
            {
                case "a":
                    return target.AsQueryable<T>().OrderBy(sortExpression);
                case "d":
                    return target.AsQueryable<T>().OrderByDescending(sortExpression);
                default:
                    return target;
            }
        }
        return target;
    }

用这个函数创建表达式(从这里的另一个答案修改而来)

        public static Expression<Func<T,object>> GetSortLambda<T>(string propertyPath)
    {
        var param = Expression.Parameter(typeof(T), "p");
        var parts = propertyPath.Split('.');
        Expression parent = param;
        foreach (var part in parts)
        {
            parent = Expression.Property(parent, part);
        }
        var sortExpression = Expression.Lambda<Func<T, object>>(parent, param);
        return sortExpression;
    }

对于解析为字符串的任何属性路径,这都可以正常工作,但对于Integers(对于Boolean则不太常见),会生成以下错误(在Int32属性的情况下):

"System.Int32"类型的表达式不能用于返回类型"System.Object"

我认为,这是因为作为返回的表达式

Expression<Func<T,object>> 

但我不知道如何克服这一点——object应该涵盖所有的属性类型,不是吗?

我可能可以通过反射来实现这一点,获得目标列的PropertyInfo(从而获得类型),但如果可能的话,我总是选择避免反射。

感谢您的指导/建议!

动态创建排序Lambda表达式

如果处理整数或日期等值类型,则可能需要Convert表达式:

public static Expression<Func<T, object>> GetSortLambda<T>(string propertyPath)
{
    var param = Expression.Parameter(typeof(T), "p");
    var parts = propertyPath.Split('.');
    Expression parent = param;
    foreach (var part in parts)
    {
        parent = Expression.Property(parent, part);
    }
    if (parent.Type.IsValueType)
    {
        var converted = Expression.Convert(parent, typeof(object));
        return Expression.Lambda<Func<T, object>>(converted, param);
    }
    else
    {
        return Expression.Lambda<Func<T, object>>(parent, param);
    }
}