C# Linq OrderBy 过滤空值或空值到最后

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13604630/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 09:09:33  来源:igfitidea点击:

C# Linq OrderBy filtering null or empty values to be last

c#linqexpression

提问by Cihan Uygun

I try to make my custom orderby extension method, i successfully worked my code but in addition i want to list null or empty or zero values last in result, anyone can help me about that issue ?

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

Here is my extension method to orderby

这是我对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);
    }

Thanks in advance

提前致谢

采纳答案by Dave Anson

Without using an extension method....

不使用扩展方法....

Create a custom IComparer<string>to check the empty values before using the default String.Compare. The first checks will return -1 instead of 1 or 1 instead of -1, if using the standard string comparison.

创建自定义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);
            }
        }
 }

Pass your EmptyStringsAreLastcomparer into the OrderByof Lambda expression. In this solution teams who have entered the race should appear alphabetical order, but the unaffiliated race entries should appear at then end.

将您的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);

回答by Rajes

The simplest way is to use

最简单的方法是使用

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

This doesn't require any extension method or custom IComparerimplementation etc.

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

var entries = repository.Race.Where(e => e.EventId == id)
                      .OrderBy(e => String.IsNullOrEmpty(e.TeamName))
                      .ThenBy(e => e.LastName)
                      .ThenBy(e => e.FirstName);

回答by aukinfo

This answer is perhaps what you were originally looking for - using your generic extension method:

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

    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);
    }

回答by Alexander - Reinstate Monica

Building on Dave Anson'sanswer, you can user Comparer.Create()to create the Comparer from a lambda. Here's an example that sorts unsortedby its myStringstring fields, with nullor empty strings appearing last.

基于Dave Anson 的回答,您可以使用Comparer.Create()从 lambda 创建比较器。这是一个unsortedmyString字符串字段排序的示例,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);
    }))

(To put them first, switch the signs on the 1constants)

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

回答by Arphenon

it works for me:

这个对我有用:

    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);
    }