假设有一种扩展方法,可根据SortMethod枚举指定的几种排序类型(即按各种属性进行排序)对IQueryable进行排序。

public static IOrderedEnumerable<AClass> OrderByX(this IQueryable<AClass> values,
    SortMethod? sortMethod)
{
    IOrderedEnumerable<AClass> queryRes = null;
    switch (sortMethod)
    {
        case SortMethod.Method1:
            queryRes = values.OrderBy(a => a.Property1);
            break;
        case SortMethod.Method2:
            queryRes = values.OrderBy(a => a.Property2);
            break;
        case null:
            queryRes = values.OrderBy(a => a.DefaultProperty);
            break;
        default:
            queryRes = values.OrderBy(a => a.DefaultProperty);
            break;
    }
    return queryRes;
}

如果sortMethodnull(即指定我不在乎值的顺序),那么有一种方法可以代替IEnumerator值作为“排序”而不必执行实际排序?

我希望能够调用此扩展,然后可能执行一些附加的ThenBy排序。

最佳答案

对于默认情况,您需要做的就是:

queryRes = values.OrderBy(a => 1);

这实际上将是一种无用的排序。由于OrderBy执行稳定排序,因此如果所选对象相等,则将维持原始顺序。请注意,由于这是IQueryable而不是IEnumerable,因此查询提供程序可能无法执行稳定的排序。在这种情况下,您需要知道保持顺序是否重要,或者只说“我不在乎结果是什么顺序,只要可以在结果上调用ThenBy即可。”

允许您避免实际排序的另一种方法是创建自己的IOrderedEnumerable实现:
public class NoopOrder<T> : IOrderedEnumerable<T>
{
    private IQueryable<T> source;
    public NoopOrder(IQueryable<T> source)
    {
        this.source = source;
    }

    public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending)
    {
        if (descending)
        {
            return source.OrderByDescending(keySelector, comparer);
        }
        else
        {
            return source.OrderBy(keySelector, comparer);
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return source.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return source.GetEnumerator();
    }
}

这样,您的查询可以是:
queryRes = new NoopOrder<AClass>(values);

请注意,以上类的结果是,如果存在对ThenBy的调用,则ThenBy实际上将是顶级排序。实际上,它将后续的ThenBy转换为OrderBy调用。 (这不足为奇; ThenBy将调用CreateOrderedEnumerable方法,并且在此代码中调用OrderBy,基本上将ThenBy转换为OrderBy。从概念上的排序角度来看,这是一种表示“所有在这种情况下,此序列中的项是相等的,但是如果您指定相等的对象应该被其他东西打破,则应这样做。

另一种“无操作排序”的思考方式是,它根据输入序列的索引对项目进行排序。这意味着这些项不是全部“相等”,这意味着顺序输入序列将是输出序列的最终顺序,并且由于输入序列中的每个项始终大于其前面的项,因此添加了额外的“tiebreaker” ”比较将无济于事,从而使后续的ThenBy调用毫无意义。如果需要此行为,则比上一个更容易实现:
public class NoopOrder<T> : IOrderedEnumerable<T>
{
    private IQueryable<T> source;
    public NoopOrder(IQueryable<T> source)
    {
        this.source = source;
    }

    public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending)
    {
        return new NoopOrder<T>(source);
    }

    public IEnumerator<T> GetEnumerator()
    {
        return source.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return source.GetEnumerator();
    }
}

10-04 11:03