是否有可能把一个IEnumerable成IOrderedEnumerable不使用排序依据?(Is

2019-07-18 10:16发布

说有一个指定的扩展方法基于几种类型的分选的订购一个IQueryable(即,由各种属性排序) SortMethod枚举。

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排序。

Answer 1:

所有你需要做的默认情况下是:

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

这将有效地成为一个空操作,排序。 因为排序依据执行稳定的排序的原始顺序将在事件所选择的对象相等来维持。 请注意,因为这是一个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);

需要注意的是上面的类的后果是,如果有一个呼叫ThenByThenBy将有效地顶层排序。 它实质上是将后续ThenByOrderBy的呼叫。 (这并不奇怪; ThenBy将调用CreateOrderedEnumerable方法,并在那里此代码调用OrderBy ,基本上是转向那ThenByOrderBy 。从一个概念性分类点,这是说,“所有的方式在这个序列中的产品在这类面前人人平等,但是如果指定相等的对象应该由别的东西来tiebroken,那么这样做。

一个是“无操作一种”思维的另一种方式是,它基于订单输入序列中的索引项。 这意味着该项目是不是所有的“相等”,这意味着该命令输入序列是输出序列的最后顺序,并且由于在输入序列中的每个项目总是比其前一个大,添加额外的“决胜局“比较会做什么,做任何后续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();
    }
}


Answer 2:

如果返回总是相同的索引值,你会得到一个IOrderedEnumerable,同时保留原始列表顺序:

case null:
     queryRes = values.OrderBy(a => 1);
     break;

顺便说一句,我不认为这是做了正确的事情。 你会得到被supposted被命令的集合,但实际上它不是。



Answer 3:

底线,IOrderedEnumerable存在仅仅是为了提供一个语法结构的排序依据()/ ThenBy()方法,阻止您试图启动与ThenBy排序条款()。 处理。 它不打算是标识集合作为下令,除非它实际上是由排序依据下令“标记”()。 因此,答案是,如果排序方法为空应该表明枚举是在一些“默认顺序”,你应该指定一个默认的顺序(作为当前实现不执行)。 这是不真诚地指出,即使通过不指定SortingMethod,你推断它的“不受任何命令”和不关心的实际顺序可枚举的时候,其实它不是有序的。

“问题”,试图固有简单地标记为收藏使用的界面是有更多的过程不是简单地整理有序。 通过执行排序方法链,如myCollection.OrderBy().ThenBy().ThenByDescending()您实际上并不排序与每个呼叫的集合; 尚未反正。 你是不是定义的“迭代”类,命名OrderedEnumerable,这将使用您在链定义了预测和比较,在目前进行排序的行为,你需要一个实际的排序元素。

Servy的回答,指出排序依据(X => 1)是一个空操作, 应该优化了SQL商忽略了现实,这个调用,对一个可枚举做,还是会做相当多的工作,并在大多数SQL商其实优化这种调用; 的OrderBy(X => 1),在大多数的LINQ提供商,生成查询用“ORDER BY 1”条款,这不仅迫使SQL提供商来执行其自己的排序,它实际上将导致改变的顺序,因为在T-SQL至少“ORDER BY 1”是指通过在选择列表的第一列订购。



文章来源: Is it possible to turn an IEnumerable into an IOrderedEnumerable without using OrderBy?