Welche Schnittstellen implementieren alle Arrays in C #?

73

Als neuer .NET 3.5-Programmierer habe ich angefangen, LINQ zu lernen, und ich habe etwas ziemlich Grundlegendes gefunden, das ich vorher nicht bemerkt habe:

Das Buch behauptet, dass jedes Array implementiert wird IEnumerable<T>(offensichtlich, sonst könnten wir LINQ nicht für Objekte auf Arrays verwenden ...). Als ich das sah, dachte ich mir, dass ich nie wirklich darüber nachgedacht habe, und fragte mich, was alle Arrays sonst noch implementieren - also untersuchte ich es System.Arraymit dem Objektbrowser (da es die Basisklasse für jedes Array in der CLR ist) und zu Meine Überraschung, es wird nicht umgesetzt IEnumerable<T>.

Meine Frage ist also: Wo ist die Definition? Ich meine, wie kann ich genau sagen, welche Schnittstellen jedes Array implementiert?

ET.
quelle

Antworten:

77

Aus der Dokumentation (Schwerpunkt Mine):

[...] die Array - Klasse implementiert die System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>und System.Collections.Generic.IEnumerable<T>generische Schnittstellen. Die Implementierungen werden Arrays zur Laufzeit zur Verfügung gestellt und sind daher für die Tools zum Erstellen von Dokumentationen nicht sichtbar.

BEARBEITEN: Wie Jb Evain in seinem Kommentar hervorhebt, implementieren nur Vektoren (eindimensionale Arrays) die generischen Schnittstellen. Ich bin mir nicht ganz sicher , warum mehrdimensionale Arrays die generischen Schnittstellen nicht implementieren, da sie die nicht generischen Gegenstücke implementieren (siehe die Klassendeklaration unten).

Die System.ArrayKlasse (dh jedes Array) implementiert auch diese nicht generischen Schnittstellen:

public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable
BoltClock
quelle
3
Ich würde sagen: erbt diese nicht generische Klasse, implementiert also diese nicht generischen Schnittstellen
abatishchev
Ich hasse es, dumme Fragen zu stellen, dann versuche ich wirklich, meine Antwort zuerst auf MSDN zu finden. Diesmal habe ich es verpasst ... Entschuldigung für die Mühe und danke für die Hilfe.
ET.
5
Ich habe nicht herabgestimmt, aber nur Vektoren (eindimensionale Arrays) implementieren die generischen Schnittstellen. Ein mehrdimensionaler Array-Typ implementiert sie nicht.
Jb Evain
@ Jb Evain: Guter Punkt! Es ist auch erwähnenswert, dass gezackte Arrays dies tun.
Hosam Aly
3
@ Hosam Aly: Gezackte Arrays sind nichts anderes als Vektoren, die zufällig andere Vektoren enthalten. Hier gibt es also keine Überraschung.
Jb Evain
68

Sie können die Antwort auf Ihre Frage empirisch mithilfe eines kleinen Codeausschnitts finden:

foreach (var type in (new int[0]).GetType().GetInterfaces())
    Console.WriteLine(type);

Das Ausführen des obigen Snippets würde zu folgender Ausgabe führen (ein .NET 4.0):

System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]

( `1bedeutet <T>)

Nach .NET 4.5( .NET Standard 1.0und später) gibt es zwei zusätzliche Schnittstellen:

System.Collections.Generic.IReadOnlyList`1[System.Int32]
System.Collections.Generic.IReadOnlyCollection`1[System.Int32]
Hosam Aly
quelle
11
+1, obwohl ich typeof(int[])eher verwendet hätte als (new int[0].GetType()...
Thomas Levesque
1
Ich mag das. Unterstützt auch das Zitat aus den MSDN-Dokumenten (vergleichen Sie dies mit der Ausgabe des Durchlaufens typeof(Array).GetType().GetInterfaces(), bei der die generischen Implementierungen fehlen).
BoltClock
16
@ Thomas: Danke für den Vorschlag. Ich habe es vorgezogen, zu verwenden (new int[0]).GetType(), um sicherzustellen, dass das Ergebnis alle Implementierungen enthält, die Arrays zur Laufzeit bereitgestellt werden , wie von @BoltClock erwähnt.
Hosam Aly
Beachten Sie, dass in .NET 4.5 (.NET Standard 1.0) zwei weitere eingeführt wurden, IReadOnlyList und IReadOnlyCollection.
Snak
55

Ab .NET 4.5 implementieren Arrays auch die Schnittstellen System.Collections.Generic.IReadOnlyList<T>und System.Collections.Generic.IReadOnlyCollection<T>.

Bei Verwendung von .NET 4.5 wird somit die vollständige Liste der von Arrays implementierten Schnittstellen (erhalten mit der in Hosam Alys Antwort dargestellten Methode ):

System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
System.Collections.Generic.IReadOnlyList`1[System.Int32]
System.Collections.Generic.IReadOnlyCollection`1[System.Int32]

Seltsamerweise scheint es vergessen worden zu sein, die Dokumentation zu MSDN zu aktualisieren , um diese beiden Schnittstellen zu erwähnen.

cr7pt0gr4ph7
quelle
1
Verknüpften Dokumentation enthält diese Information, aber etwas versteckt: „Beginnend mit dem .NET Framework 2.0, der ArrayKlasse implementiert die System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>und System.Collections.Generic.IEnumerable<T>. Generische Schnittstellen Die Implementierungen auf Arrays zur Laufzeit zur Verfügung gestellt werden, und als Ergebnis wird die generischen Schnittstellen zu tun wird in der Deklarationssyntax für die Array-Klasse nicht angezeigt. "
Tim Schmelter
1

Vorsichtig auf Array-Schnittstellen können sie diese implementieren, aber tatsächlich tun sie dies nicht wirklich ... Machen Sie sich mit dem folgenden Code vertraut:

            var x = new int[] { 1, 2, 3, 4, 5 };
        var y = x as IList<int>;
        Console.WriteLine("The IList:" + string.Join(",", y));
        try
        {
            y.RemoveAt(1);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        Console.WriteLine(string.Join(",", y));

Es wird die folgende Ausgabe erzeugt: Ergebnis

Das Parsen funktioniert also, aber es wird nicht alles unterstützt, was aus Sicht der Sammlung mit fester Länge korrekt ist, aber völlig falsch, wenn Sie wirklich glauben, dass es sich um eine Liste handelt. Es geht das Liskov-Prinzip von SOLID :(.

Für die Prüfung schnell diesen Willen zu helfen.

Adrian P.
quelle
Genialer Punkt. Ich kann den Standpunkt von Microsoft darin sehen, dass ein Array eine "Anzahl" hat und indizierbar ist. Aber Sie haben Recht, es kann RemoveAt (x) nicht implementieren, da dies eine Neudimensionierung des Arrays bedeuten würde. Ich denke, das wäre möglich, da Verweise auf eine Variable von der CLR verschoben werden können. - und ohne sie ist die Liskov-Substitution tatsächlich aus dem Fenster. Ich denke, die Lösung wäre, IList in IFixedList und IFlexibleList zu zerlegen und Array nur die IFixedList implementieren zu lassen. Trotzdem sehe ich das Casting in den meisten Fällen als Annehmlichkeit an.
Simon Miller
Tatsächlich hat die IList <T> -Schnittstelle über ICollection <T> auch eine Eigenschaft namens IsReadOnly. Eine IList <T> -Implementierung ist daher nicht erforderlich, um die Aufrufe, die die Sammlung manipulieren, tatsächlich zu verarbeiten, wenn IsReadOnly als true zurückgegeben wird, was für ein Array gilt.
Kasper Cottaar
0

Ich habe die Implementierung von IList<T>, ICollection<T>, IEnumerable<T>in der SZArrayHelperverschachtelten Klasse des Arrays gefunden.

Aber ich muss dich warnen - dort wirst du noch viel mehr Fragen finden ...

Die Referenz

Danach habe ich nur noch einen bekommen - there_is_no_array;)

Kamerton
quelle