2009-08-05 7 views
12

Ich möchte einige verschiedene Algorithmen für die Praxis umzusetzen, nur um zu sehen, wie schlecht ich wirklich bin und besser werden: pC#: Wie implementieren IOrderedEnumerable <T>

Auch immer, ich dachte, ich würde versuchen IEnumerable<T> und IOrderedEnumerable<T> zu verwenden und andere .Net-Sammlungstypen, nur um kompatibel zu sein (so dass das, was ich schreibe, später einfacher verwendet werden kann).

Aber ich kann keinen Weg finden, eine Instanz von IOrderedEnumerable<T> anders als die Verwendung der Methoden OrderBy und ThenBy zurückzugeben. Ich denke also, ich muss meine eigene Klasse erstellen, die diese Schnittstelle implementiert. Aber die Schnittstelle macht für mich keinen Sinn, um ehrlich zu sein. Es könnte, aber ich bin mir nicht sicher.

habe ich eine leere Klasse, hinzugefügt, um die Schnittstelle und bekam dann ReSharper für mich leer Implementierungen hinzuzufügen. Es sieht wie folgt aus:

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

Was ich nicht verstehe, ist die CreateOrderedEnumerable Methode. Was genau soll es machen? Nun, ich denke, es würde natürlich eine geordnete Aufzählung schaffen, aber wie? Soll der Sortieralgorithmus selbst dorthin gehen? Und was wird es sortieren? Es gibt keine Sammlung von Elementen, die zu dieser Methode gehören. Wo also soll die Sammlung abgerufen werden? Wie würdest du die Klasse benutzen? Soll es zum Beispiel als private Hilfsklasse in etwas implementiert werden, das Dinge sortieren muss?

Dann anstelle eines MyOrderedEnumerable<T> : IOrderedEnumerable<T>, könnten Sie eine QuickSorter<T> : IOrderedEnumerable<T> haben, die eine Sammlung in seinem Konstruktor nahm und es sortiert, wenn das CreateOrderedEnumerable Methode aufgerufen wurde ... aber was würde dann passieren, wenn jemand GetEnumerator genannt und begann vor diesem Verfahren aufzuzählen war aufgerufen worden?


Haha, nur entdeckte ich etwas ähnliches vor einer Weile here gefragt hatte. Aber das war nur, wenn es möglich war, eins zurückzugeben. Also ich denke, diese Frage eine Antwort auf die ich dort bekam eine Antwort ist =)

Antwort

11

Ich habe ein sample implementation Sie betrachten könnte. Es ist nicht so konzipiert, um effizient zu sein, aber es sollte Ihnen den Anfang machen.

Grundsätzlich ist ein IOrderedEnumerable<T> braucht nur eine Vorstellung von seiner gegenwärtigen Ordnung haben, so kann es eine neue erstellen. Vorausgesetzt, dass Sie bereits ein IComparer<T> haben Sie einen neuen bauen, indem er sagte etwas wie:

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

Also im Grunde erstellen Sie eine Kette von comparers von der „am wenigsten signifikanten“ bis zum „bedeutendsten“ gehen. Sie müssen auch die „absteigend“ Bit in dort setzen, aber das ist einfach :)

In der Probe oben verbunden, die drei verschiedenen Aspekte werden in drei verschiedenen Klassen vertreten bereits in MiscUtil:

  • ReverseComparer : kehrt aN IComparer<T> ‚s Ergebnisse
  • LinkedComparer vorhanden: erstellt einen Vergleich an einem Vorsprung von den ursprünglichen Elemente Schlüssel basiert, zum Delegieren an: mit einem Master und einem Slave
  • ProjectionComparer schafft ein Vergleich von zwei, ein weiterer Vergleich, um diese Schlüssel zu vergleichen.

Vergleicher sind ideal für die Verkettung so.

+0

Sweet! Werde es sofort ausprobieren =) – Svish

+0

Also würde es sich auf der Grundlage des neuen Vergleichs, den du ihm gegeben hast, neu anordnen? oder? nicht sicher, ob ich das verstanden habe ... – Svish

+0

Es würde sich nicht neu ordnen - es würde eine neue Sequenz mit der neuen Reihenfolge erstellen, basierend auf der alten Reihenfolge und dem neuen Vergleich. Es würde nicht die alte Sequenz selbst verwenden, außer um die ursprünglichen ungeordneten Daten zu erhalten. Sehen Sie sich den Code für weitere Details an :) –

1

Vermutlich wird Ihre Klasse eine interne Speichervariable haben, die IEnumerable (List<T> zum Beispiel) implementiert. Die Implementierung dieser Methode ist in einem solchen Fall einfach:

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

Das ist falsch. CreateOrderedEnumerable wird von der LINQ-Funktion "ThenBy" aufgerufen und muss die bereits vorhandene Reihenfolge beibehalten. Wenn Sie Ihr Snippet zum Implementieren von CreateOrderedEnumerable verwenden, wird die Reihenfolge überschrieben, sodass Ihre Implementierung die Semantik der Schnittstelle durchbricht. – Zarat

Verwandte Themen