Neulich beim Programmieren hatte ich das Anliegen, Klasseninstanzen, die in einer ArrayList gespeichert waren, zu sortieren. Natürlich nicht irgendwie, sondern nach einem bestimmten Feld, das ich zur Compilezeit noch nicht kenne, das aber zur Ausführzeit bekannt wird. Die Testklasse heißt schlicht "Schiff": <Serializable()> Public Class Schiff Implements IComparable ' (1) Public Name As String Public Heimathafen As String Public Baujahr As Integer Public Kaufpreis As Single Public Stapellauf As New Date Public Shared SortierFeld As String = "Heimathafen" ' (2) Public Shared Sortierung As SortOrder = SortOrder.Ascending Public Sub New(ByVal Name As String, ByVal Heimathafen As String, _ ByVal Baujahr As Integer, ByVal Kaufpreis As Single, ByVal Stapellauf As Date) Me.Name = Name Me.Heimathafen = Heimathafen Me.Baujahr = Baujahr Me.Kaufpreis = Kaufpreis Me.Stapellauf = Stapellauf End Sub Public Sub New() End Sub Public Function CompareTo(ByVal obj As Object) _ As Integer Implements System.IComparable.CompareTo ' (3) Dim s As Schiff s = CType(obj, Schiff) Dim f1 As Reflection.FieldInfo f1 = Me.GetType.GetField(Me.SortierFeld) Dim f2 As Reflection.FieldInfo f2 = s.GetType.GetField(Me.SortierFeld) Wert1 = f1.GetValue(Me) Wert2 = f2.GetValue(s) If Wert1 Is Nothing Or Wert2 Is Nothing Then Exit Function ' (4) ' (5) If f1.FieldType Is GetType(Integer) Or f1.FieldType Is GetType(Short) Or f1.FieldType Is GetType(Long) Then If Wert1 > Wert2 Then Return 1 ElseIf Wert1 < Wert2 Then Return -1 Else Return 0 End If ElseIf f1.FieldType Is GetType(Double) Or f1.FieldType Is GetType(Single) Then If Wert1 > Wert2 Then Return 1 ElseIf Wert1 < Wert2 Then Return -1 Else Return 0 End If ElseIf f1.FieldType Is GetType(String) Then Return String.Compare(Wert1, Wert2) ElseIf f1.FieldType Is GetType(Date) Then Return Date.Compare(Wert1, Wert2) ElseIf f1.FieldType Is GetType(Decimal) Then Return Decimal.Compare(Wert1, Wert2) ElseIf f1.FieldType Is GetType(DateTime) Then Return DateTime.Compare(Wert1, Wert2) End If End Function End Class (1): implements IComparable brauchen wir für das Überschreiben der "CompareTo"-Methode, die die Hauptarbeit beim Sortieren für uns erledigt. (2): interessant sind hier die beiden "shared"-Variablen, mit denen wir nachher den Sortiervorgang steuern. Natürlich könnte man das ganze auch in einen Verwalter auslagern, aber der Einfachheit halber habe ich das gleich in der Klasse selber gemacht. In "SortierFeld" gibt man einfach den Namen des Feldes an, nach dem wir sortieren wollen. "Sortierung" gibt an, ob wir aufsteigend oder absteigend sortieren wollen, aber dazu später mehr. (3): Das Herzstück der Sortierung ist diese Funktion, die wir über die Implementierung der Schnittstelle "IComparable" einfach überschreiben. Wir holen uns zuerst die Werte der beiden Felder, die wir über die Klassenvariable "Sortierfeld" bestimmt haben. (f1 und f2 sind Verweise auf die jeweiligen Klassenelemente) Man beachte, dass einer der Vergleichswerte in der aktuellen Instanz ruht (Me) und der andere von außen als Parameter kommt. Wir vergleichen also quasi das Haus des Nachbarn mit unserem eigenen (4): falls eins der Felder nichts zurückgibt, dann steigen wir aus. Ein Grund hierfür wäre beispielsweise die Nicht-Existenz des Feldes! Dies kann vorliegen, falls in der ArrayList Instanzen von verschiedenen Klassen gespeichert sind. (5): nun folgen die von uns implementierten Vergleiche. Ganzzahlvergleiche werden der Bequemlichkeit halber zusammengefasst. Hier kann man auch eigene Definitionen einbringen, etwa eine Rundung auf zwei Nachkommastellen bei single, vier bei double, Missachtung von negativem Vorzeichen oder dergleichen. Bei den komplexeren Datentypen verwenden wir einfach die bereits existierenden Compare-Methoden gemäß dem Prinzip des intelligenten Faulseins Nun ein Beispiel zur praktischen Anwendung: ' Das einzige, was wir tun müssen, ist festzulegen, wonach wir ' sortieren wollen. Hier im Beispiel suchen wir uns einfach mal ' das Baujahr aus und wir wollen absteigende Resultate erhalten. Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Schiff.SortierFeld = "Baujahr" Schiff.Sortierung = SortOrder.Descending End Sub ' Diese Funktion wurde hier einem Steuerelement zugewiesen, nach dessen Klick ' der Code ausgeführt wird. (geht natürlich auch anders, etwa mit Hilfe eines ' eigenen Verwalters, der die Daten hält; sprengt jetzt aber vielleicht etwas den Rahmen) Private Sub Sortieren_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Sortieren.Click ' Erstellen einiger Instanzen Dim s1 As New Schiff("Albatros", "Rostock", 1864, 492.9, New Date(1863, 3, 5)) Dim s2 As New Schiff("Ubena von Bremen", "Bremen", 1380, 482.5, New Date(1379, 8, 27)) Dim s3 As New Schiff("Adler von Lübeck", "Lübeck", 1565, 285.7, New Date(1563, 12, 9)) Dim s4 As New Schiff("Rath von Riga", "Riga", 1341, 450.34, New Date(1340, 11, 24)) ' Füllen der ArrayList mit den Schiffen Dim AL As New ArrayList AL.Add(s1) AL.Add(s2) AL.Add(s3) AL.Add(s4) AL.Sort() ' Das tolle bei der ganzen Sache ist, dass wir die eigentliche Sortierung ' nicht programmieren müssen, denn das kann die ArrayList ganz allein. ' Wir müssen lediglich sagen, nach welchen Gesichtspunkten zwei Instanzen ' unserer eigenen Klasse verglichen werden sollen. ' dies wiederum haben wir in der CompareTo-Methode schon gemacht. ' Die Arbeit des sortierens erfolgt intern mit Aufruf von "sort". If Schiff.Sortierung = SortOrder.Descending Then AL.Reverse() 'wir sortieren immer aufsteigend und drehen bei Bedarf um End If ' Ausgabe um zu sehen, was passiert ist Dim s As String s = AL.Item(0).Name & " " & AL.Item(0).Baujahr & " " & _ AL.Item(0).kaufpreis & vbNewLine s &= AL.Item(1).Name & " " & AL.Item(1).Baujahr & " " & _ AL.Item(1).kaufpreis & vbNewLine s &= AL.Item(2).Name & " " & AL.Item(2).Baujahr & " " & _ AL.Item(2).kaufpreis & vbNewLine s &= AL.Item(3).Name & " " & AL.Item(3).Baujahr & " " & _ AL.Item(3).kaufpreis & vbNewLine MsgBox(s) End Sub Dieser Tipp wurde bereits 20.192 mal aufgerufen.
Anzeige
![]() ![]() ![]() Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
sevZIP40 Pro DLL ![]() Zippen und Unzippen wie die Profis! Mit nur wenigen Zeilen Code statten Sie Ihre Anwendungen ab sofort mit schnellen Zip- und Unzip-Funktionen aus. Hierbei lassen sich entweder einzelnen Dateien oder auch gesamte Ordner zippen bzw. entpacken. Tipp des Monats ![]() Manfred Bohn IndexOf für mehrdimensionale Arrays Die generische Funktion "IndexOf" ermittelt das erste Auftreten eines bestimmten Wertes in einem n-dimensionalen Array Access-Tools Vol.1 ![]() Über 400 MByte Inhalt Mehr als 250 Access-Beispiele, 25 Add-Ins und ActiveX-Komponenten, 16 VB-Projekt inkl. Source, mehr als 320 Tipps & Tricks für Access und VB |
||||||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |