动态创建排序Lambda表达式

时间:2014-09-28 21:38:15

标签: c# linq sorting dynamic lambda

我想使用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;
    }

这对于解析为字符串的任何属性路径都是预期的,但对于整数(并且布尔值较少),会生成以下错误(在Int32属性的情况下):

  

表达类型&#39; System.Int32&#39;不能用于返回类型&#39; System.Object&#39;

我认为这是因为表达式以

的形式返回
Expression<Func<T,object>> 

但是我无法弄清楚如何克服这一点 - object应该涵盖所有类型的财产,不应该吗?

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

任何指导/建议表示赞赏!

1 个答案:

答案 0 :(得分:4)

如果要处理整数或日期等值类型,则可能需要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);
    }
}