2009-08-05 9 views
12

Quiero poner en práctica algunas diversos algoritmos para la práctica, sólo para ver lo mal que realmente soy y para conseguir mejor: pC#: ¿Cómo implementar IOrderedEnumerable <T>

De todas formas, pensé que iba a tratar de utilizar IEnumerable<T> y IOrderedEnumerable<T> y otros tipos de colecciones .Net para ser compatibles (para que lo que escribo pueda usarse más fácilmente más adelante).

Pero no puedo encontrar una forma de devolver una instancia de IOrderedEnumerable<T> que no sea con los métodos de extensión OrderBy y ThenBy. Así que supongo que tengo que crear mi propia clase que implemente esta interfaz. Pero la interfaz no tiene sentido para mí para ser honesto. Podría, pero no estoy seguro.

Creé una clase vacía, agregué la interfaz y luego obtuve ReSharper para agregar implementaciones vacías para mí. Se ve así:

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(); 
    } 
} 

Lo que no entiendo es el método CreateOrderedEnumerable. ¿Qué es exactamente lo que debe hacer? Bueno, supongo que, por supuesto, crearía un enumerable ordenado, pero ¿cómo? ¿Se supone que el algoritmo de clasificación debe ir allí? ¿Y qué ordenará? No hay una colección de artículos que entren en ese método, entonces, ¿dónde se pretende ordenar la colección? ¿Cómo usarías la clase? ¿Está destinado a ser implementado como, por ejemplo, una clase de ayuda privada dentro de algo que necesita ordenar cosas?

Entonces, en lugar de un MyOrderedEnumerable<T> : IOrderedEnumerable<T>, es posible que tenga un QuickSorter<T> : IOrderedEnumerable<T> que tuvo una colección en su constructor y lo arreglaron cuando ese CreateOrderedEnumerable método se llama ... pero lo que entonces pasaría si alguien llama GetEnumerator y comenzó a enumerar antes de que el método había sido llamado?


Jaja, acaba de descubrir que había pedido algo similar hace un tiempo here. Pero eso era solo si era posible devolver uno. Así que supongo que esta pregunta es una respuesta a la única respuesta que obtuve =)

Respuesta

11

Tengo un sample implementation que podría mirar. No está diseñado para ser eficiente de ninguna manera, pero debe comenzar.

Básicamente un IOrderedEnumerable<T> solo necesita tener una idea de su orden actual, por lo que puede crear uno nuevo. Asumiendo que ya tiene un IComparer<T> a construir uno nuevo, diciendo algo como:

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);   
} 

Así que básicamente crear una cadena de comparadores que van desde el "menos significativo" hasta el "más significativo". También es necesario poner el "descendente" poco de allí, pero eso es fácil :)

En la muestra vinculado anteriormente, los tres aspectos diferentes están representadas en tres clases diferentes ya presente en MiscUtil:

  • ReverseComparer : invierte los resultados de un IComparer<T> existentes 's
  • LinkedComparer: crea un comparador de dos, con un maestro y un esclavo
  • ProjectionComparer: crea un comparador sobre la base de una proyección de los elementos originales a las llaves, delegando otro comparador para comparar esas llaves.

Los correladores son ideales para encadenar juntos de esta manera.

+0

Sweet! Lo verificará de inmediato =) – Svish

+0

¿Se reordenaría a sí mismo según el nuevo comparador que le proporcione? ¿o? no estoy seguro si entendí que ... – Svish

+0

No se reordenaría a sí mismo; crearía una nueva secuencia con el nuevo pedido, basado en el pedido anterior y la nueva comparación. No utilizaría la secuencia anterior en sí misma, excepto para obtener los datos originales no ordenados. Mira el código para más detalles :) –

1

Presumiblemente, su clase tendrá alguna variable de almacenamiento interno que implemente IEnumerable (List<T> por ejemplo). La implementación de este método es simple en tal caso:

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

Esto está mal. CreateOrderedEnumerable es llamado por la función LINQ "ThenBy" y debe preservar el orden existente. Usar su fragmento para implementar CreateOrderedEnumerable anulará la orden, haciendo que su implementación rompa la semántica de la interfaz. – Zarat

Cuestiones relacionadas