C#: как реализовать IOrderedEnumerable

Я хочу реализовать несколько различных алгоритмов для практики, просто чтобы увидеть, насколько я действительно плох и стать лучше: p

в любом случае, я думал, что попытаюсь использовать 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 метод был вызван... но что будет, если кто-нибудь позвонит?--8--> и начал перечислять до того, как был вызван этот метод?


ха-ха, только что обнаружил, что я спросил что-то подобное некоторое время назад здесь. Но это было как раз то, что можно было вернуть. Поэтому я думаю, что этот вопрос является ответом на один ответ, который я получил там=)

2 ответов


у меня есть пример реализации вы могли бы посмотреть. Он не предназначен для того, чтобы быть эффективным, но он должен заставить вас начать.

в основном 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);        
}

таким образом, в основном вы создаете цепочку компараторов, идущих от " наименее значимого "до"наиболее значимого". Вам также нужно поместить туда бит" нисходящий", но это легко:)

в приведенном выше примере три разных аспекта представлены в трех разных классах, уже присутствующих в MiscUtil:

  • ReverseComparer: меняет существующий С
  • LinkedComparer: создает один компаратор из двух, с одним мастером и одним рабом
  • ProjectionComparer: создает компаратор на основе проекции из исходных элементов к ключам, делегируя другому компаратору для сравнения этих ключей.

Comparers для сцепления вместе.


предположительно, ваш класс будет иметь некоторую внутреннюю переменную хранения, которая реализует 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);
}