Neulich hatte ich einen sehr merkwürdigen Fehler bei der Verwendung eines SortedDictionary<string, string>. Ich erhielt eine ArgumentException mit der Beschreibung „Ein Eintrag mit dem gleichen Schlüssel ist bereits vorhanden.“
Das Ganze war umso verwunderlicher, da die Daten 1:1 aus einem normalen Dictionary<string, string> übernommen wurden und demzufolge der Fehler schon an dieser Stelle hätte auftreten müssen.
Um auf die Ursache des Fehlers zu kommen, habe ich folgende Testklasse geschrieben:
public class Sorter : IComparer { public Sorter() { var sortedDictionary = new SortedDictionary<string, string>(this); sortedDictionary.Add("test", "Hallo Welt"); sortedDictionary.Add("Test", "Hallo zurück"); } public int Compare(string x, string y) { x = x.ToLower(); y = y.ToLower(); return x.CompareTo(y); } }
Mach beachte die Zeile 12 und 13. Die Sortierung sollte case-insensitive erfolgen. Dies hat aber zur Folge, dass nicht der Angegebene Schlüssel „Test“ eingefügt, sondern der aus dem Vergleich, nämlich „test“. Ohne diese Zeilen würden der Fehler nicht auftreten.
Für mich ist dieses Verhalten nicht ganz nachvollziehbar und es fühlt sich ganz leicht nach einem Bug an. Denn obwohl die Vergleichsmethode den Wert „0“ für „gleich“ zurück gibt, sollte dennoch der ursprünglich angegebene Schlüssel verwendet werden.
31. Januar 2013, 21:22 Uhr
Ich habe bisher noch nicht probiert, die Fehlersituation nachzustellen, allerdings scheint es mir so, als würde das SortedDictionary nicht darauf ausgelegt sein, dass Schlüssel „gleich“ sind und verwendet deshalb auch für die Gleichheitsprüfung der Schlüssel den mitgegebenen „passenden“ Comparer.
Ein Workaround wäre es, wenn der Comparer nur dann eine Gleichheit feststellt, wenn die beiden Texte (case sensitiv) gleich sind. Das heißt also, dass das Ergebnis des einfachen Vergleichs mittels String.CompareTo zurück gegeben werden kann, wenn es nicht auf Gleichheit hindeutet und ansonsten die Groß- und Kleinschreibung überprüft werden muss. Da könnte man dann bei dem ersten Festgestellten Unterschied die Zeichenfolge als „größer“ bezeichnen, welche an der ersten gefundenen Stelle einen Großbuchstaben besitzt.
Ein evtl. aufwändigere Variante wäre ein eigenes SortedDictionary, welches für die Gleichheitsprüfung nicht den Comparer, sondern Equals oder den Vergleichsoperator verwendet.
Man muss aber auch bedenken, dass das SortedDictionary versucht, für jedes Element eine eindeutige Position zu finden. Wenn 2 Elemente einen gleichwertigen Index haben, dann kann nicht bestimmt werden, in welcher Reihenfolge sie enthalten sein sollen und insofern ist das Verhalten durchaus sinnvoll.
Richard