Saschas Weblog

ESCde Developer Blog

  Home :: Kontakt :: RSS Feed
  30 Posts :: 0 Artikel :: 10 Kommentare :: 32 Trackbacks

Archiv

Post Kategorien

ESCde

ESCde Blogger

Ich war auf der Suche nach einem einigermaßen sinnvollen Beispiel für die Programmierung von Powershell Cmdlets. Das erste Cmdlet soll Informationen aus ID3Tags von MP3-Dateien auslesen. Man muss das Rad nicht jedesmal neu erfinden, daher verwende ich die Bibliothek ID3Sharp von Chris Woodbury, die man auf sourceforge.net finden kann.

Die MP3-Dateien aus einem Verzeichnis werden nacheinander eingelesen. Für jede Datei werden die Informationen aus dem ID3-Tag in einer Instanz vom Typ ID3Tag zurückgegeben. Diese besitzt lediglich einige öffentliche Eigenschaften für die gängigen Informationen wie Artist, Title, Album, etc. Diese einzelnen Instanzen von ID3Tags werden in einer generischen Liste gesammelt.

List<ID3Tag> id3Tags = new List<ID3Tag>();

Es wäre schön, auf diese Liste nun Filter und Sortierungen anzuwenden. Geht natürlich auch ;-)

Fangen wir mit dem Sortieren an. Die generische Klasse List<T> bietet von Haus aus eine Sort() Methode in drei möglichen Überladungen.

List<T>.Sort () ohne weitere Argumente verwendet den default comparer. Das bedeutet, dass der Typ T das IComparable- oder das generische IComparable-Interface implementieren muss. Da dies bei ID3Tag nicht der Fall ist, würde sich die Liste bei einem Sort()-Aufruf mit einer InvalidOperationException bedanken.

Für die beiden anderen Überladungen wird eine Vergleichsmethode benötigt, die als Parameter zwei Variablen vom Typ T verarbeiten muss, in unserem Falle also zwei Objekte vom Typ ID3Tag. Der Rückgabewert der Methode ist -1, 0 oder 1, je nachdem, ob x kleiner, gleich, oder größer y ist. Ich überlasse hier die Berechnung des Rückgabewertes der String.CompareTo()-Methode der Artist- bzw. Title-Eigenschaft.

Für die Sortierung List<T>.Sort (Generic Comparison) muss die Vergleichsmethode in einer statischen Methode mit den oben erwähnten Parameter definiert werden:

public static int CompareID3TagsByArtist(ID3Tag x, ID3Tag y) { if (x.Artist == y.Artist) return x.Title.CompareTo(y.Title); else return x.Artist.CompareTo(y.Artist); }

Diese Methode habe ich in einer Klasse SearchFilter erstellt. Der Aufruf zum Sortieren der Liste lautet daher:

id3Tags.Sort(SearchFilter.CompareID3TagsByArtist);

Die letzte Möglichkeit, List<T>.Sort(Generic IComparer), verstaut die Vergleichsmethode in einer eigenen Klasse, die das generische IComparer<T>-Interface implementiert. Um das Interface zu implementieren, muss exakt eine Methode erstellt werden - die Vergleichsmethode. Die ganze Klasse sieht dann so aus:

internal class Mp3Comparer : IComparer<ID3Tag> { #region IComparer<ID3Tag> Members public int Compare(ID3Tag x, ID3Tag y) { if (x.Artist == y.Artist) return x.Title.CompareTo(y.Title); else return x.Artist.CompareTo(y.Artist); } #endregion }

Für den Sortieraufruf muss dann ein Objekt vom Type Mp3Comparer erzeugt werden, welches an die Sortmethode übergeben wird.

Mp3Comparer mc = new Mp3Comparer(); id3Tags.Sort(mc);

Als letztes Schmankerl fehlt noch ein aufsteigendes oder absteigendes Sortieren. Dafür lässt sich der Code für die Mp3Comparer Klasse zum Beispiel wie folgt ändern:

#region IComparer<ID3Tag> Members public int Compare(ID3Tag x, ID3Tag y) { if (x.Artist == y.Artist) return (int)sortType * x.Title.CompareTo(y.Title); else return (int)sortType * x.Artist.CompareTo(y.Artist); } #endregion public Mp3Comparer() { this.sortType = SortType.Ascending; } public Mp3Comparer(SortType sortType) { this.sortType = sortType; } private SortType sortType; public enum SortType {Descending = -1, Ascending = 1}

Es ist ein neuer Konstruktor hinzugekommen, der eine Sortierrichtung als Parameter akzeptiert. Ist ein Nicht-Standardkonstruktor definiert, muss auch der Standardkonstruktor explizit angegeben werden. Die bisherige Sortierrichtung war aufsteigend. Dies soll auch der Standardwert sein, wenn keine Richtung angegeben wurde. Soll absteigend sortiert werden, wird der Rückgabewert von Compare gerade mit -1 multipliziert.

Um die Liste nun absteigend zu sortieren, wird folgender Aufruf verwendet:

Mp3Comparer mc = new Mp3Comparer(Mp3Comparer.SortType.Descending); id3Tags.Sort(mc);
veröffentlicht am 28.02.2007 19:08