Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Sortieren mit dem IComparer Interface

Geschrieben von: Christoph Wille
Kategorie: C#

This printed page brought to you by AlphaSierraPapa

In vielen Fällen sind die Elemente in einer Collection nicht so angeordnet, wie man sie gerne hätte. Oft möchte man auch zur Laufzeit eine Umsortierung erzwingen, zB die Elemente aufsteigend statt absteigend sortieren. Anhand der Sort Methode der ArrayList Klasse zeige ich, daß dies nicht weiter schwierig ist.

Die Sort Methode der ArrayList Klasse hat mehrere Overloads, und an einige kann ein Comparer übergeben werden, der das IComparer Interface implementiert. Dieses Interface hat nur eine einzige Methode - Compare. Dieser werden zwei Objekte x und y übergeben, und je nach dem wie die beiden Objekte vergleichen, sieht der Rückgabewert wie folgt aus:

Ich möchte das gleich an einem Beispiel verdeutlichen:

/// <summary>Implements ascending sort algorithm</summary>
public class AscendingComparer : IComparer
{
  public int Compare(object objA, object objB)
  {
    return String.Compare(objA.ToString(), objB.ToString());
  }
}

Die Klasse AscendingComparer implementiert das IComparer Interface, und besitzt eine einzige Methode, nämlich Compare. Dieser Methode werden zwei Objekte übergeben, und der Vergleich zwischen beiden wird mittels String.Compare durchgeführt (wir sortieren also Strings). Diese liefert - wie der Zufall es so will - die gleichen Rückgabewerte wie die Compare Methode von IComparer.

Will man einen DescendingComparer implementieren, muß man nur die Parameter an String.Compare in der umgekehrten Reihenfolge übergeben:

/// <summary>Implements descending sort algorithm</summary>
public class DescendingComparer : IComparer
{
  public int Compare(object objA, object objB)
  {
    return String.Compare(objB.ToString(), objA.ToString());
  }
}

Damit hätten wir zwei Comparer zum Experimentieren zur Verfügung. Zur Demonstration wird eine ArrayList einmal unsortiert, aufsteigend und schließlich absteigend sortiert ausgegeben:

  public static void Main(string[] args)
  {
    // fill a sample array list
    ArrayList al = new ArrayList();
    ComparerSampleMain.FillArrayList(ref al);

    // print the unsorted list
    Console.WriteLine("-- Unsorted --");
    foreach(string strCurrent in al) {
      Console.WriteLine(strCurrent);
    }

    // sort ascending, then print
    al.Sort(new AscendingComparer());
    Console.WriteLine("\r\n-- Sorted ascending --");
    for (int i=0; i < al.Count; i++) {
      Console.WriteLine(al[i]); 
    }

    // finally, sort descending, then print
    al.Sort(new DescendingComparer());
    Console.WriteLine("\r\n-- Sorted descending --");
    foreach(string strCurrent in al) {
      Console.WriteLine(strCurrent);
    }
  }

Der Sort Methode wird jeweils eine Instanz des gewünschten Comparers übergeben:

al.Sort(new AscendingComparer());

Und Sort verwendet dann diesen Comparer, um während des Umsortierens die Vergleiche zwischen zwei Elementen vorzunehmen. Umsortieren ist also keine Hexerei unter .NET.

Automatische Klassengenerierung in SharpDevelop

Natürlich kann man bei so einem einfachen Interface wie IComparer leicht den notwendigen Infrastrukturcode selbst schreiben. Sobald ein Interface aber mehr als drei Methoden hat, wird diese Arbeit allerdings lästig, und kostet Zeit, die wir zum Schreiben der Implementierung besser verwenden könnten. Also Zeit, daß uns ein Tool die Aufgabe der Vorgenerierung des Klassengrundgerüsts abnimmt.

In SharpDevelop gibt es einen Class Wizard, der genau das kann, und zwar sowohl für C# und auch VB.NET. Und zu demonstrieren, wie einfach das geht, fügen wir dem aktuellen Projekt einfach eine neue Datei dazu:

In der New File Dialogbox wählen wir in der Gruppe C# den New Class Wizard aus.

Unsere erste Entscheidung ist der Klassenname (hier MySpecialComparer). Die Klasse, die generiert wird, soll public sein, und wir leiten von keiner Basisklasse ab (keine Auswahl in Available Base Classes):

Mit Next geht es weiter im Wizard. Jetzt folgt die Auswahl der Interfaces, die wir in der Klasse MySpecialComparer implementieren wollen. Hier ist IComparer aus dem System.Collections Namespace bereits ausgewählt:

Damit sind wir fast fertig. Auf der letzten Wizardseite können wir noch unseren bevorzugten Programmierstil auswählen, und auch diverse (Open Source) Lizenzen automatisiert einfügen lassen. Der wichtigste Punkt aber sind die drei Checkboxen, die die ganze Coding-Arbeit für uns übernehmen:

Damit ist der Wizard auch schon fertig, und generiert uns folgenden Code (einige Kommentare sind zur Verkürzung herausgenommen):

namespace IComparerSample
{
  using System;
  
  /// <summary>
  /// TODO - Add class summary
  /// </summary>
  /// <remarks>
  ///   created by - Administrator
  ///   created on - 4/16/2002 1:13:33 PM
  /// </remarks>
  public class MySpecialComparer : object, System.Collections.IComparer
  {
    
    /// <summary>
    /// Default constructor - initializes all fields to default values
    /// </summary>
    public MySpecialComparer()
    {
    }
    
    /// <summary>
    /// TODO - add method description
    /// </summary>
    /// <remarks>
    /// Interface method from IComparer
    /// 
    /// </remarks>
    /// <param name='x'>TODO - add parameter description</param>
    /// <param name='y'>TODO - add parameter description</param>
    public virtual int Compare(object x, object y)
    {
      throw new System.NotImplementedException();
    }
  }
}

Neben einem vollständigen Klassengrundgerüst bekommen wir auch gleich die entsprechende vorausgefüllte XML Dokumentation mitgeneriert. Durch die Verwendung dieses Wizards kann man bei der Implementierung von Klassen einiges an Zeit einsparen!

Schlußbemerkung

Die Implementierung des IComparer Interfaces ist schnell möglich. Wer mehrere Interfaces (oder größere) implementieren möchte, sollte sich SharpDevelop und den New Class Wizard genauer anschauen.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20020417.zip

Verwandte Artikel

Arrays mit Index und Schlüssel
http:/www.aspheute.com/artikel/20020124.htm
Das foreach Statement
http:/www.aspheute.com/artikel/20000720.htm
Schleifenbefehle in C#
http:/www.aspheute.com/artikel/20000717.htm
Verwendung von Arrays in C#
http:/www.aspheute.com/artikel/20000731.htm

Links zu anderen Sites

SharpDevelop
http://www.icsharpcode.net/opensource/sd/

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.