Der Titel ist einfach genug, warum kann ich nicht:
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.AddRange(MethodThatReturnAnotherDic());
c#
.net
dictionary
Sorgerecht
quelle
quelle
Antworten:
Ein Kommentar zur ursprünglichen Frage fasst dies ziemlich gut zusammen:
Warum? Nun, wahrscheinlich, weil das Verhalten beim Zusammenführen von Wörterbüchern nicht in einer Weise begründet werden kann, die den Framework-Richtlinien entspricht.
AddRange
existiert nicht, weil ein Bereich für einen assoziativen Container keine Bedeutung hat, da der Datenbereich doppelte Einträge zulässt. Wenn Sie beispielsweise eine habenIEnumerable<KeyValuePair<K,T>>
, schützt diese Sammlung nicht vor doppelten Einträgen.Das Hinzufügen einer Sammlung von Schlüssel-Wert-Paaren oder sogar das Zusammenführen von zwei Wörterbüchern ist unkompliziert. Das Verhalten beim Umgang mit mehreren doppelten Einträgen ist jedoch nicht so.
Wie sollte sich die Methode verhalten, wenn es sich um ein Duplikat handelt?
Ich kann mir mindestens drei Lösungen vorstellen:
Wie sollte der Status des ursprünglichen Wörterbuchs sein, wenn eine Ausnahme ausgelöst wird?
Add
wird fast immer als atomare Operation implementiert: Sie ist erfolgreich und aktualisiert den Status der Sammlung, oder sie schlägt fehl, und der Status der Sammlung bleibt unverändert. DaAddRange
dies aufgrund doppelter Fehler fehlschlagen kann, besteht die Möglichkeit, das Verhalten konsistent zu haltenAdd
, darin, es atomar zu machen, indem eine Ausnahme für ein Duplikat ausgelöst wird, und den Status des ursprünglichen Wörterbuchs unverändert zu lassen.Als API-Konsument wäre es mühsam, doppelte Elemente iterativ entfernen zu müssen, was bedeutet, dass
AddRange
eine einzige Ausnahme ausgelöst werden sollte, die alle doppelten Werte enthält.Die Wahl läuft dann auf Folgendes hinaus:
Es gibt Argumente für die Unterstützung beider Anwendungsfälle. Fügen Sie
IgnoreDuplicates
dazu der Signatur ein Flag hinzu?Das
IgnoreDuplicates
Flag (wenn es auf true gesetzt ist) würde ebenfalls eine erhebliche Beschleunigung bewirken, da die zugrunde liegende Implementierung den Code für die doppelte Überprüfung umgehen würde.Jetzt haben Sie ein Flag, mit dem
AddRange
beide Fälle unterstützt werden können, das jedoch einen undokumentierten Nebeneffekt hat (was die Framework-Designer sehr hart vermieden haben).Zusammenfassung
Da es beim Umgang mit Duplikaten kein klares, konsistentes und erwartetes Verhalten gibt, ist es einfacher, nicht alle zusammen zu behandeln und zunächst nicht die Methode bereitzustellen.
Wenn Sie ständig Wörterbücher zusammenführen müssen, können Sie natürlich Ihre eigene Erweiterungsmethode zum Zusammenführen von Wörterbüchern schreiben, die sich so verhält, wie es für Ihre Anwendung (en) funktioniert.
quelle
AddMultiple
ist anders alsAddRange
, unabhängig davon, ob die Implementierung wackelig sein wird: Wirfst du eine Ausnahme mit einem Array aller doppelten Schlüssel? Oder werfen Sie eine Ausnahme auf den ersten doppelten Schlüssel, auf den Sie stoßen? Wie sollte der Status des Wörterbuchs sein, wenn eine Ausnahme ausgelöst wird? Makellos oder alle Schlüssel, die erfolgreich waren?Add
- wickeln Sie entweder jedeAdd
in a eintry...catch
und fangen Sie die Duplikate auf diese Weise ab. oder verwenden Sie den Indexer und überschreiben Sie den ersten Wert mit dem späteren Wert; oder überprüfen Sie die Verwendung vorab,ContainsKey
bevor Sie dies versuchenAdd
, und behalten Sie so den ursprünglichen Wert bei. Wenn das Framework eineAddRange
oderAddMultiple
-Methode hätte, wäre die einzige einfache Möglichkeit, das Geschehene zu kommunizieren, eine Ausnahme, und die damit verbundene Handhabung und Wiederherstellung wäre nicht weniger kompliziert.Ich habe eine Lösung:
...
Habe Spaß.
quelle
ToList()
, ein Wörterbuch ist einIEnumerable<KeyValuePair<TKey,TValue>
. Die zweite und dritte Methodenmethode werden auch ausgelöst, wenn Sie einen vorhandenen Schlüsselwert hinzufügen. Keine gute Idee, suchten SieTryAdd
? Schließlich kann die zweite durchWhere(pair->!dic.ContainsKey(pair.Key)...
ToList()
ist keine gute Lösung, also habe ich den Code geändert. Sie können verwenden,try { mainDic.AddRange(addDic); } catch { do something }
wenn Sie sich für die dritte Methode nicht sicher sind. Die zweite Methode funktioniert perfekt.Falls jemand wie ich auf diese Frage stößt, ist es möglich, "AddRange" mithilfe von IEnumerable-Erweiterungsmethoden zu erreichen:
Der Haupttrick beim Kombinieren von Wörterbüchern ist der Umgang mit den doppelten Schlüsseln. Im obigen Code ist es der Teil
.Select(grp => grp.First())
. In diesem Fall wird einfach das erste Element aus der Gruppe der Duplikate verwendet, aber Sie können dort bei Bedarf eine komplexere Logik implementieren.quelle
dict1
nicht verwendet wird?var combined = dict1.Concat(dict2).GroupBy(kvp => kvp.Key, dict1.Comparer).ToDictionary(grp => grp.Key, grp=> grp.First(), dict1.Comparer);
Ich vermute, dass dem Benutzer keine ordnungsgemäße Ausgabe darüber vorliegt, was passiert ist. Wie würden Sie mit dem Zusammenführen von zwei Wörterbüchern umgehen, bei denen sich einige Schlüssel überschneiden, da sich Schlüssel in einem Wörterbuch nicht wiederholen können? Sicher könnte man sagen: "Es ist mir egal", aber das verstößt gegen die Konvention, falsch zurückzugeben / eine Ausnahme für das Wiederholen von Schlüsseln auszulösen.
quelle
Add
Abgesehen davon kann dies mehr als einmal vorkommen. Es würde die gleiche werfenArgumentException
das derAdd
Fall ist, oder ?NamedElementException
??), der entweder anstelle oder als innerException einer ArgumentException ausgelöst wird und das benannte Element angibt, das in Konflikt steht ... ein paar verschiedene Optionen, würde ich sagenDu könntest das tun
oder verwenden Sie eine Liste für die Adressierung und / oder verwenden Sie das obige Muster.
quelle
MethodThatReturnAnotherDic
. Es kommt aus dem OP. Bitte überprüfen Sie die Frage und meine Antwort erneut.Wenn Sie mit einem neuen Wörterbuch arbeiten (und keine vorhandenen Zeilen zu verlieren haben), können Sie ToDictionary () immer aus einer anderen Liste von Objekten verwenden.
In Ihrem Fall würden Sie also Folgendes tun:
quelle
Dictionary<string, string> dic = SomeList.ToDictionary...
Wenn Sie wissen, dass Sie keine doppelten Schlüssel haben werden, können Sie Folgendes tun:
Es wird eine Ausnahme ausgelöst, wenn ein doppeltes Schlüssel / Wert-Paar vorhanden ist.
Ich weiß nicht, warum dies nicht im Rahmen ist; sollte sein. Es gibt keine Unsicherheit; Wirf einfach eine Ausnahme. Bei diesem Code wird eine Ausnahme ausgelöst.
quelle
var caseInsensitiveDictionary = new Dictionary<string, int>( StringComparer.OrdinalIgnoreCase);
?Fühlen Sie sich frei, Erweiterungsmethode wie folgt zu verwenden:
quelle
Hier ist eine alternative Lösung mit c # 7 ValueTuples (Tupelliterale)
Gebraucht wie
quelle
Wie bereits erwähnt, liegt der Grund für die Nichtimplementierung darin, dass
Dictionary<TKey,TVal>.AddRange
Sie auf verschiedene Weise mit Fällen umgehen können, in denen Duplikate vorhanden sind. Dies ist auch der Fall fürCollection
oder Schnittstellen wieIDictionary<TKey,TVal>
,ICollection<T>
usw.Nur
List<T>
implementiert, und Sie werden feststellen , dass dieIList<T>
Schnittstelle nicht, aus den gleichen Gründen: das erwartete Verhalten , wenn eine Reihe von Werten zu einer Sammlung hinzugefügt breit variieren kann, je nach Kontext.Der Kontext Ihrer Frage legt nahe, dass Sie sich keine Sorgen um Duplikate machen. In diesem Fall haben Sie eine einfache Oneliner-Alternative mit Linq:
quelle