Siehe die Definition der System.Array- Klasse
public abstract class Array : IList, ...
Theoretisch sollte ich in der Lage sein, dieses Stück zu schreiben und glücklich zu sein
int[] list = new int[] {};
IList iList = (IList)list;
Ich sollte auch in der Lage sein, jede Methode aus der iList aufzurufen
ilist.Add(1); //exception here
Meine Frage ist nicht, warum ich eine Ausnahme bekomme, sondern warum Array IList implementiert .
c#
arrays
ilist
liskov-substitution-principle
oleksii
quelle
quelle
Antworten:
Da ein Array einen schnellen Zugriff über den Index ermöglicht und
IList
/IList<T>
is die einzigen Sammlungsschnittstellen sind, die dies unterstützen. Ihre eigentliche Frage lautet also vielleicht: "Warum gibt es keine Schnittstelle für konstante Sammlungen mit Indexern?" Und darauf habe ich keine Antwort.Es gibt auch keine schreibgeschützten Schnittstellen für Sammlungen. Und ich vermisse diese noch mehr als eine konstante Größe mit Indexer-Oberfläche.
IMO sollte es abhängig von den Merkmalen einer Sammlung mehrere (generische) Sammlungsschnittstellen geben. Und die Namen hätten auch anders sein sollen,
List
denn etwas mit einem Indexer ist IMO wirklich dumm.IEnumerable<T>
ICollection<T>
IList<T>
Ich denke, die aktuellen Kollektionsoberflächen sind schlecht gestaltet. Da sie jedoch Eigenschaften haben, die Ihnen sagen, welche Methoden gültig sind (und dies ist Teil des Vertrags dieser Methoden), verstößt dies nicht gegen das Substitutionsprinzip.
quelle
add
und kann daher nicht durch etwas ersetzt werden, das dies tut, wenn diese Fähigkeit erforderlich ist.IsFixedSize
undIsReadOnly
Eigenschaften überprüfen sollten. Es verstößt definitiv gegen das Tell, Don't Ask-Prinzip und das Prinzip der geringsten Überraschung . Warum eine Schnittstelle implementieren, wenn Sie nur Ausnahmen für 4 der 9 Methoden auslösen?Der Bemerkungsabschnitt der Dokumentation für
IList
sagtOffensichtlich fallen Arrays in die Kategorie mit fester Größe, so dass es durch die Definition der Schnittstelle sinnvoll ist.
quelle
Array
wird dieAdd
Methode explizit implementiert , wodurch das Risiko eines versehentlichen Aufrufs verringert wird.IList
, die sowohl das Ändern als auch das Hinzufügen / Entfernen nicht zulässt . Dann sind die Dokumentationen nicht mehr korrekt. : PWeil nicht alle
IList
s veränderbar sind (sieheIList.IsFixedSize
undIList.IsReadOnly
) und Arrays sich sicherlich wie Listen mit fester Größe verhalten.Wenn Ihre Frage wirklich lautet: "Warum wird eine nicht generische Schnittstelle implementiert ?", Lautet die Antwort, dass diese vor der Einführung von Generika vorhanden waren.
quelle
IList
selbst Ihnen sagt, dass es möglicherweise nicht veränderbar ist. Wenn es in der Tat ist garantiert wandelbar zu sein , und das Array sagten Sie sonst, dann wäre es die Regel zu brechen.IList<T>
und nicht im Falle von Nicht-GenerikaIList
: Enterprisecraftsmanship.com/2014/11/22/…Es ist ein Erbe, das wir aus Zeiten haben, in denen nicht klar war, wie man mit schreibgeschützten Sammlungen umgeht und ob Array schreibgeschützt ist oder nicht. In der IList-Schnittstelle befinden sich IsFixedSize- und IsReadOnly-Flags. Das IsReadOnly-Flag bedeutet, dass die Sammlung überhaupt nicht geändert werden kann, und IsFixedSize bedeutet, dass die Sammlung Änderungen zulässt, jedoch keine Elemente hinzufügt oder entfernt.
Zum Zeitpunkt von .Net 4.5 war klar, dass einige "Zwischen" -Schnittstellen erforderlich sind, um mit schreibgeschützten Sammlungen zu arbeiten,
IReadOnlyCollection<T>
undIReadOnlyList<T>
wurden eingeführt.Hier ist ein großartiger Blog-Beitrag, der die Details beschreibt: Nur-Lese-Sammlungen in .NET
quelle
Die Definition der IList-Schnittstelle lautet "Stellt eine nicht generische Sammlung von Objekten dar, auf die über den Index einzeln zugegriffen werden kann." Das Array erfüllt diese Definition vollständig und muss daher die Schnittstelle implementieren. Eine Ausnahme beim Aufrufen der Add () -Methode ist "System.NotSupportedException: Collection hatte eine feste Größe" und ist aufgetreten, weil das Array seine Kapazität nicht dynamisch erhöhen kann. Seine Kapazität wird beim Erstellen des Array-Objekts definiert.
quelle
Wenn ein Array IList (und transitiv ICollection) implementiert, wird die Linq2Objects-Engine vereinfacht, da das Umwandeln der IEnumerable in IList / ICollection auch für Arrays funktionieren würde.
Beispielsweise ruft Count () die Array.Length unter der Haube auf, da sie in ICollection umgewandelt wird und die Implementierung des Arrays Length zurückgibt.
Ohne dies hätte die Linq2Objects-Engine keine spezielle Behandlung für Arrays und eine schreckliche Leistung, oder sie müsste den Code verdoppeln und eine Sonderbehandlung für Arrays hinzufügen (wie dies für IList der Fall ist). Sie müssen sich dafür entschieden haben, dass Array stattdessen IList implementiert.
Das ist meine Einstellung zu "Warum".
quelle
Außerdem Implementierungsdetails LINQ Letzte Überprüfungen für IList. Wenn die Liste nicht implementiert wurde, müssten entweder 2 Überprüfungen alle letzten Aufrufe verlangsamen oder Last auf einem Array mit O (N).
quelle