30

我尝试制作我的自定义 orderby 扩展方法,我成功地处理了我的代码,但另外我想在结果中最后列出 null 或空或零值,任何人都可以帮助我解决这个问题吗?

这是我对 orderby 的扩展方法

    public static IQueryable<T> OrderBy<T>(this IQueryable<T> q, string SortField, bool isAsc)
    {
        //var nullExpr = Expression.Constant(null, typeof(T));
        var param = Expression.Parameter(typeof(T), "p");
        var prop = Expression.Property(param, SortField);
        var exp = Expression.Lambda(prop, param);
        string method = isAsc ? "OrderBy" : "OrderByDescending";
        Type[] types = new Type[] { q.ElementType, exp.Body.Type };
        var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);
        return q.Provider.CreateQuery<T>(mce);
    }

提前致谢

4

6 回答 6

46

最简单的方法是使用

OrderBy(e => String.IsNullOrEmpty(e.TeamName)

这不需要任何扩展方法或自定义IComparer实现等。

var entries = repository.Race.Where(e => e.EventId == id)
                      .OrderBy(e => String.IsNullOrEmpty(e.TeamName))
                      .ThenBy(e => e.LastName)
                      .ThenBy(e => e.FirstName);
于 2014-03-21T06:26:32.903 回答
26

不使用扩展方法....

在使用默认值之前创建自定义IComparer<string>以检查空值String.Compare。如果使用标准字符串比较,第一次检查将返回 -1 而不是 1 或 1 而不是 -1。

/// <summary>
/// Returns -1 instead of 1 if y is IsNullOrEmpty when x is Not.
/// </summary>
public class EmptyStringsAreLast : IComparer<string>
{
    public int Compare(string x, string y)
        {
            if (String.IsNullOrEmpty(y) && !String.IsNullOrEmpty(x))
            {
                return -1;
            }
            else if (!String.IsNullOrEmpty(y) && String.IsNullOrEmpty(x))
            {
                return 1;
            }
            else
            {
                return String.Compare(x, y);
            }
        }
 }

EmptyStringsAreLast将您的比较器传递给OrderByLambda 表达式。在此解决方案中,参加比赛的团队应按字母顺序显示,但非附属比赛条目应出现在最后。

var entries = repository.Race.Where(e => e.EventId == id)
                          .OrderBy(e => e.TeamName, new EmptyStringsAreLast())
                          .ThenBy(e => e.LastName)
                          .ThenBy(e => e.FirstName);
于 2013-02-01T08:02:21.713 回答
3

这个答案可能是您最初寻找的 - 使用您的通用扩展方法:

    public static IQueryable<T> OrderByFieldNullsLast<T>(this IQueryable<T> q, string SortField, bool Ascending)
    {
        //We are rebuilding .OrderByDescending(p => p.SortField.HasValue).ThenBy(p => p.SortField)
        //i.e. sort first by whether sortfield has a value, then by sortfield asc or sortfield desc

        //create the expression tree that represents the generic parameter to the predicate
        var param = Expression.Parameter(typeof(T), "p");

        //create an expression tree that represents the expression p=>p.SortField.HasValue 
        var prop = Expression.Property(param, SortField);
        var hasValue = Expression.Property(prop, "HasValue");
        var exp = Expression.Lambda(hasValue, param);

        string method = "OrderByDescending";
        Type[] types = new Type[] { q.ElementType, exp.Body.Type };
        var orderByCallExpression = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);

        //now do the ThenBy bit,sending in the above expression to the Expression.Call
        exp = Expression.Lambda(prop, param);
        types = new Type[] { q.ElementType, exp.Body.Type };
        method = Ascending ? "ThenBy" : "ThenByDescending";
        var ThenByCallExpression = Expression.Call(typeof(Queryable), method, types,orderByCallExpression, exp);


        return q.Provider.CreateQuery<T>(ThenByCallExpression);
    }
于 2015-06-21T21:47:59.043 回答
1

基于Dave Anson 的回答,您可以使用Comparer.Create()从 lambda 创建 Comparer。unsorted这是一个按其myString字符串字段排序的示例,null最后出现或空字符串。

var sorted = unsorted.OrderBy(x => x.myString, Comparer<string>.Create((x, y) => { 
             if ( string.IsNullOrEmpty(y) && !string.IsNullOrEmpty(x)) return -1;
        else if (!string.IsNullOrEmpty(y) &&  string.IsNullOrEmpty(x)) return +1;
        else return string.Compare(x, y);
    }))

(把它们放在第一位,切换1常量上的符号)

于 2016-05-03T16:53:33.987 回答
0

这个对我有用:

    private static IQueryable<T> GetOrderQuery<T>(this IQueryable<T> q, BaseFilterCollection filter)
    {
        q = q.OrderBy(GetExpression<T>(filter.SortField));

        var param = Expression.Parameter(typeof(T), "p");
        var prop = Expression.Property(param, filter.SortField);
        var exp = Expression.Lambda(prop, param);
        string method = filter.SortDirection == SortDirectionType.Asc ? "ThenBy" : "ThenByDescending";
        Type[] types = { q.ElementType, exp.Body.Type };
        var rs = Expression.Call(typeof(Queryable), method, types, q.Expression, exp);
        return q.Provider.CreateQuery<T>(rs);
    }

    private static Expression<Func<T, bool>> GetExpression<T>(string sortField)
    {
        ParameterExpression param = Expression.Parameter(typeof(T), "p");
        Expression prop = Expression.Property(param, sortField);

        var info = typeof(T).GetProperty(sortField, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        Expression exp = Expression.Equal(prop, info.PropertyType.IsValueType 
            ? Expression.Constant(Activator.CreateInstance(info.PropertyType)) 
            : Expression.Constant(null));

        return Expression.Lambda<Func<T, bool>>(exp, param);
    }
于 2016-07-15T11:49:52.660 回答
0

你不需要复杂化,最简单的方法是做这样的事情:

YourList.OrderByDescending(x => string.IsNullOrEmpty(x.value)

使用 OrderByDescending 或 OrderBy 取决于您是想在开头还是最后看到空字符串。

问候

于 2021-03-01T17:45:02.570 回答