Ich lief in einen Fall, wo die Tatsache, dass List.AsReadOnly()
gibt ReadOnlyCollection
anstelle von IReadOnlyCollection
machte die Dinge schwer für mich. Da die zurückgegebene Sammlung die Value
einer Dictionary
war, konnte sie nicht automatisch auf eine IReadOnlyCollection
umgestellt werden. Das schien merkwürdig, und nach Überprüfung des .Net-Quellcodes habe ich bestätigt, dass die AsReadOnly()
-Methode für List
etwas anderes tut als für Dictionary
, nämlich das Zurückgeben der konkreten Klasse anstelle der Schnittstelle.Warum gibt List.AsReadOnly eine ReadOnlyCollection zurück, aber Dictionary.AsReadOnly gibt ein IReadOnlyDictionary zurück?
Kann jemand erklären, warum das ist? Es scheint ein Nachteil, diese Inkonsistenz zu haben, vor allem, weil wir die Schnittstellen möglichst und vor allem in der Öffentlichkeit nutzen wollen.
In meinem Code dachte ich zuerst, dass, da mein Konsument nur eine private Methode war, ich seine Parametersignatur von IReadOnlyDictionary<T, IReadOnlyCollection<T>>
zu IReadOnlyDictionary<T, ReadOnlyCollection<T>>
ändern konnte. Aber dann wurde mir klar, dass dieser es wie die private Methode aussehen lässt könnte die Sammlung Werte ändern, so habe ich eine ärgerliche explizite Umwandlung in den früheren Code, um richtig die Schnittstelle zu verwenden:
.ToDictionary(
item => item,
item => (IReadOnlyCollection<T>) relatedItemsSelector(item)
.ToList()
.AsReadOnly() // Didn't expect to need the direct cast
)
Oh, und da Ich bekomme immer Kovarianz und Kontravarianz verwirrt, könnte mir bitte jemand sagen, welches die automatische Besetzung verhindert, und versuchen, mich auf eine vernünftige Weise daran zu erinnern, wie man sich an sie für die Zukunft erinnert? (zB Sammlungen sind nicht ______variant [co/contra] für _____ [Eingabe/Ausgabe] -Parameter.) Ich verstehe, warum dies nicht sein kann, weil es viele Implementierungen der Schnittstelle geben kann und es nicht sicher ist, alle zu konvertieren einzelne Elemente des Wörterbuchs zum gewünschten Typ. Es sei denn, ich bläst sogar diesen einfachen Aspekt und ich nicht verstehe es, in welchem Fall ich hoffe, Sie können mir helfen, mich richtig zu stellen ...
Oh oh oh! Ich nahm an, dass es nicht automatisch umwandeln würde, weil es * nicht * kovariant war, aber jetzt sehe ich, dass, weil 'IReadOnlyCollection' nur gelesen wird, der Compiler sehen kann, dass es sicher ist, vom abgeleiteten Typ in die Basis zu konvertieren . Wenn das der Fall ist, warum musste ich dann eine explizite Besetzung machen? – ErikE
Kovarianz und Kontravarianz treten nur dann auf, wenn Sie zwischen zwei generischen * Interfaces * umwandeln und den * -Typ-Parameter * ändern (von Basis zu abgeleitet oder umgekehrt). Die Besetzung, die Sie verwendet haben, ist nur eine Besetzung - sie ist erlaubt, weil 'ReadOnlyCollection' 'IReadOnlyList ' 'implementiert. –
Oh, oops, das macht Sinn. Es wird klarer. Warum konnte es nicht implizit wirken? – ErikE