2009-08-05 28 views
12

我想要实现的做法有些不同的算法,只是为了看看我有多糟糕真的很和,以获得更好:对C#:如何实现IOrderedEnumerable <T>

不管怎么说,我想我会尝试使用IEnumerable<T>IOrderedEnumerable<T>和其他.Net集合类型只是为了兼容(以便我写的内容稍后可以更容易地使用)。

但我找不到一种方法来返回IOrderedEnumerable<T>的实例,而不是使用OrderBy和ThenBy扩展方法。所以我想我必须创建自己的类来实现这个接口。但接口对我来说不太合理,说实话。它可能,但我不确定。

我创建了一个空类,添加了接口,然后让ReSharper为我添加空实现。它看起来像这样:

class MyOrderedEnumerable<T> : IOrderedEnumerable<T> 
{ 
    /// <summary> 
    /// Performs a subsequent ordering on the elements of an <see cref="T:System.Linq.IOrderedEnumerable`1"/> according to a key. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Linq.IOrderedEnumerable`1"/> whose elements are sorted according to a key. 
    /// </returns> 
    /// <param name="keySelector">The <see cref="T:System.Func`2"/> used to extract the key for each element.</param><param name="comparer">The <see cref="T:System.Collections.Generic.IComparer`1"/> used to compare keys for placement in the returned sequence.</param><param name="descending">true to sort the elements in descending order; false to sort the elements in ascending order.</param><typeparam name="TKey">The type of the key produced by <paramref name="keySelector"/>.</typeparam><filterpriority>2</filterpriority> 
    public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending) 
    { 
     throw new NotImplementedException(); 
    } 

    /// <summary> 
    /// Returns an enumerator that iterates through the collection. 
    /// </summary> 
    /// <returns> 
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>1</filterpriority> 
    public IEnumerator<T> GetEnumerator() 
    { 
     throw new NotImplementedException(); 
    } 

    /// <summary> 
    /// Returns an enumerator that iterates through a collection. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>2</filterpriority> 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

什么我不明白的是CreateOrderedEnumerable方法。究竟是什么意思?那么,我想它当然会创建一个有序的枚举,但是如何?排序算法本身应该放在那里?它会排序?没有收集任何项目进入该方法,那么它是为了获得收集订单?你将如何使用课堂?这是否意味着要实施例如一个私人帮手类内的东西,需要排序的东西?

然后代替MyOrderedEnumerable<T> : IOrderedEnumerable<T>的,你可能有一个QuickSorter<T> : IOrderedEnumerable<T>是花了集合在其构造和分类的时候,那个CreateOrderedEnumerable方法被调用......但随后会发生什么,如果有人打电话GetEnumerator,开始该方法之前枚举被称为?


哈哈,刚发现我刚才问了一些类似的东西here。但那只是如果有可能返回一个。所以我想这个问题是对我到达的答案的答复=)

回答

11

我有一个sample implementation你可以看看。它不是以任何方式高效的,但它应该让你开始。

基本上IOrderedEnumerable<T>只需要有一个当前排序的想法,所以它可以创建一个新的。假设你已经有一个IComparer<T>你建立一个新的说法是这样的:

int Compare(T first, T second) 
{ 
    if (baseComparer != null) 
    { 
     int baseResult = baseComparer.Compare(first, second); 
     if (baseResult != 0) 
     { 
      return baseResult; 
     } 
    } 
    TKey firstKey = keySelector(first); 
    TKey secondKey = keySelector(second); 

    return comparer.Compare(firstKey, secondKey);   
} 

所以基本上你创建comparers从“最显著”上升到“最显著”走出链。你也需要把位在那里“降”,但很容易:)

在上面挂的样品,在三个不同的方面进行了三个不同的等级来表示已存在于MiscUtil

  • ReverseComparer :反转现有IComparer<T>的结果
  • LinkedComparer:从两个创建一个比较器,具有一个主站和一个从
  • ProjectionComparer:创建基于从原始项密钥的投影一个比较器,委托给另一个比较器来比较这些键。

比较器很适合像这样链接在一起。

+0

甜!将立即检查它=) – Svish 2009-08-05 18:29:51

+0

所以它会根据你给它的新比较器重新排序?要么?不知道我是否明白... – Svish 2009-08-05 18:43:33

+0

它不会重新排序 - 它会根据旧订单和新比较创建新订单并添加新订单。它不会使用旧序列本身,除非得到原始的无序数据。请看代码以获取更多详细信息:) – 2009-08-05 18:46:46

1

假设你的班级有一些内部存储变量,它们实现IEnumerable(例如List<T>)。这种方法的实现很简单,在这种情况下:

private List<T> data = new List<T>(); 

public IOrderedEnumerable<CalculationResult> CreateOrderedEnumerable<TKey>(Func<CalculationResult, TKey> keySelector, IComparer<TKey> comparer, bool descending) 
{ 
    return descending ? 
     data.OrderByDescending(keySelector, comparer) 
    : data.OrderBy(keySelector, comparer); 
} 
+0

这是错误的。 CreateOrderedEnumerable由“ThenBy”LINQ函数调用,并且必须保留已经存在的顺序。使用你的代码片段实现CreateOrderedEnumerable将覆盖顺序,导致你的实现中断接口语义。 – Zarat 2015-05-29 14:50:22