C# 带排序的动态Linq查询,末尾为空

C# 带排序的动态Linq查询,末尾为空,c#,asp.net,linq,sorting,dynamic-linq,C#,Asp.net,Linq,Sorting,Dynamic Linq,我正在尝试构建一个ASP.NET页面,该页面在可空字段上排序。我想做的是,如果sortable字段中有空值,总是将这些行抛出到列表的末尾。否则,它们会显示在列表的开头,我可以想象在进入A-Z排序元素之前,页面和空值行页面 我在ASP.NET框架中工作。可排序列的解决方案是针对以下GridViewDataSource构建动态查询: public static class QueryExtensions { public static IQueryable<T> SortBy<T&

我正在尝试构建一个ASP.NET页面,该页面在可空字段上排序。我想做的是,如果sortable字段中有空值,总是将这些行抛出到列表的末尾。否则,它们会显示在列表的开头,我可以想象在进入A-Z排序元素之前,页面和空值行页面

我在ASP.NET框架中工作。可排序列的解决方案是针对以下GridViewDataSource构建动态查询:

public static class QueryExtensions {
public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName) {
    if (source == null) {
        throw new ArgumentNullException("source");
    }
    // DataSource control passes the sort parameter with a direction
    // if the direction is descending          
    int descIndex = propertyName.IndexOf(" DESC");
    if (descIndex >= 0) {
        propertyName = propertyName.Substring(0, descIndex).Trim();
    }

    if (String.IsNullOrEmpty(propertyName)) {
        return source;
    }

    ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
    MemberExpression property = Expression.Property(parameter, propertyName);
    LambdaExpression lambda = Expression.Lambda(property, parameter);

    string methodName = (descIndex < 0) ? "OrderBy" : "OrderByDescending";

    Expression methodCallExpression = Expression.Call(typeof(Queryable), methodName,
                                        new Type[] { source.ElementType, property.Type },
                                        source.Expression, Expression.Quote(lambda));

    return source.Provider.CreateQuery<T>(methodCallExpression);
}
公共静态类查询扩展{
公共静态IQueryable排序方式(此IQueryable源,字符串propertyName){
if(source==null){
抛出新的ArgumentNullException(“源”);
}
//DataSource控件传递带有方向的sort参数
//如果方向是下降的
int descIndex=propertyName.IndexOf(“DESC”);
如果(描述索引>=0){
propertyName=propertyName.Substring(0,descIndex.Trim();
}
if(String.IsNullOrEmpty(propertyName)){
返回源;
}
ParameterExpression参数=Expression.parameter(source.ElementType,String.Empty);
MemberExpression属性=Expression.property(参数,propertyName);
LambdaExpression lambda=Expression.lambda(属性、参数);
string methodName=(descIndex<0)?“OrderBy”:“OrderByDescending”;
Expression methodCallExpression=Expression.Call(typeof(Queryable)、methodName、,
新类型[]{source.ElementType,property.Type},
source.Expression,Expression.Quote(lambda));
返回source.Provider.CreateQuery(methodCallExpression);
}
}

因为我在这个框架内工作,所以我不会改变这个函数的工作方式。相反,我试图用此签名重载该方法:

public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName, bool nullsToEnd)
publicstaticiqueryable-SortBy(此IQueryable源代码,字符串propertyName,boolnullstoend)
我遇到的问题是,我无法弄清楚如何编辑“methodName”以专门允许这种排序(末尾为空的A-Z)发生

有什么办法可以解决这个问题吗


谢谢

我认为没有一个方法名称本身可以满足您的要求。相反,在这个场景中,您需要选择一个不同的方法重载,一个采用自定义IComparer实例的方法重载。然后,您需要实现一个包装Comparer.Default的IComparer,在不涉及null时返回该比较器的结果,并在不涉及null时将null排序到末尾

请注意,如果您希望OrderBy和OrderByDescending案例的结尾都为null,则需要相应地调整IComparer实现。要么让它同时处理空值和升序/降序选项,要么让它在执行“降序”情况时将空值排序到开头(就个人而言,由于您必须根据升序/降序状态调整IComparer,因此我会继续让IComparer处理升序/降序部分)

例如:

class NullsAtEndComparer<T> : IComparer<T> where T : class
{
    private static readonly IComparer<T> _baseComparer = Comparer<T>.Default;

    private readonly bool _ascending;

    public NullsAtEndComparer(bool ascending = true)
    {
        _ascending = ascending;
    }

    public int Compare(T t1, T t2)
    {
        if (object.ReferenceEquals(t1, t2))
        {
            return 0;
        }

        if (t1 == null)
        {
            return 1;
        }

        if (t2 == null)
        {
            return -1;
        }

        return _ascending ? _baseComparer.Compare(t1, t2) : _baseComparer.Compare(t2, t1);
    }
}
class NullsAtEndComparer:IComparer其中T:class
{
私有静态只读IComparer _baseComparer=Comparer.Default;
私有只读布尔值;
公共NullsAtEndComparer(布尔升序=真)
{
_上升=上升;
}
公共整数比较(t1,t2)
{
if(object.ReferenceEquals(t1,t2))
{
返回0;
}
如果(t1==null)
{
返回1;
}
如果(t2==null)
{
返回-1;
}
返回_升序?_baseComparer.Compare(t1,t2):_baseComparer.Compare(t2,t1);
}
}

然后对于“结尾处为空”的场景,只需始终使用OrderBy方法并为该方法提供上述IComparer实现的实例。

请注意我的编辑,其中我修复了排序错误。比较器需要确保所有相同的输入对都被认为是相等的,即使它们都为null。使用object.ReferenceEquals()可以实现这一点,并且在将同一对象作为两个操作数传递时,还提供了快捷方式优化。