Neue Antwort im Lichte von Hans 'Antwort
Dank der Antwort von Hans können wir sehen, dass die Implementierung etwas komplizierter ist, als wir vielleicht denken. Sowohl der Compiler als auch die CLR sind sehr bemüht , den Eindruck zu erwecken, den ein Array-Typ implementiert IList<T>
- aber die Array-Varianz macht dies schwieriger. Im Gegensatz zu der Antwort von Hans implementieren die Array-Typen (eindimensional, ohnehin nullbasiert) die generischen Sammlungen direkt, da der Typ eines bestimmten Arrays nicht System.Array
- das ist nur der Basistyp des Arrays. Wenn Sie einen Array-Typ fragen, welche Schnittstellen er unterstützt, enthält er die generischen Typen:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Ausgabe:
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]
Bei eindimensionalen, auf Null basierenden Arrays wird das Array in Bezug auf die Sprache auch wirklich implementiert IList<T>
. Abschnitt 12.1.2 der C # -Spezifikation sagt dies aus. Unabhängig von der zugrunde liegenden Implementierung muss sich die Sprache so verhalten, als ob die Art der T[]
Implementierung IList<T>
wie bei jeder anderen Schnittstelle. Aus dieser Perspektive ist die Schnittstelle wird mit einigen der Mitglieder umgesetzt explizit umgesetzt (wie Count
). Das ist die beste Erklärung auf Sprachebene für das, was vor sich geht.
Beachten Sie, dass dies nur für eindimensionale Arrays gilt (und nullbasierte Arrays, nicht dass C # als Sprache etwas über nicht nullbasierte Arrays aussagt). T[,]
nicht implementiert IList<T>
.
Aus CLR-Sicht ist etwas Funkigeres los. Sie können die Schnittstellenzuordnung für die generischen Schnittstellentypen nicht abrufen. Beispielsweise:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Gibt eine Ausnahme von:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
Warum also die Verrücktheit? Nun, ich glaube, es liegt wirklich an der Array-Kovarianz, die eine Warze im Typsystem IMO ist. Obwohl IList<T>
es nicht kovariant ist (und nicht sicher sein kann), ermöglicht die Array-Kovarianz Folgendes:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... was es wie Geräte aussehen lässt , wenn es nicht wirklich ist.typeof(string[])
IList<object>
Die CLI-Spezifikation (ECMA-335) Partition 1, Abschnitt 8.7.1, enthält Folgendes:
Ein Signaturtyp T ist genau dann mit einem Signaturtyp U kompatibel, wenn mindestens einer der folgenden Punkte zutrifft
...
T ist ein auf Null basierendes Rang-1-Array V[]
und U
ist IList<W>
, und V ist Array-Element-kompatibel mit W.
(Es wird nicht wirklich erwähnt ICollection<W>
oder IEnumerable<W>
was ich für einen Fehler in der Spezifikation halte.)
Bei Nichtvarianz geht die CLI-Spezifikation direkt mit der Sprachspezifikation einher. Aus Abschnitt 8.9.1 von Partition 1:
Zusätzlich implementiert ein erstellter Vektor mit dem Elementtyp T die Schnittstelle System.Collections.Generic.IList<U>
, wobei U: = T. (§8.7)
(Ein Vektor ist ein eindimensionales Array mit einer Nullbasis.)
In Bezug auf die Implementierungsdetails führt die CLR eindeutig eine funky Zuordnung durch, um die Zuweisungskompatibilität hier zu gewährleisten: Wenn a string[]
nach der Implementierung von gefragt wird ICollection<object>.Count
, kann dies nicht ganz normal gehandhabt werden. Zählt dies als explizite Schnittstellenimplementierung? Ich denke, es ist vernünftig, es so zu behandeln, denn wenn Sie nicht direkt nach der Schnittstellenzuordnung fragen, verhält es sich aus sprachlicher Sicht immer so.
Was ist mit ICollection.Count
?
Bisher habe ich über die generischen Schnittstellen gesprochen, aber dann gibt es die nicht generischen ICollection
mit ihrer Count
Eigenschaft. Dieses Mal sind wir können das Interface - Mapping erhalten, und in der Tat ist die Schnittstelle implementiert direkt durch System.Array
. Die Dokumentation für die ICollection.Count
Eigenschaftsimplementierung in Array
besagt, dass sie mit expliziter Schnittstellenimplementierung implementiert ist.
Wenn sich jemand vorstellen kann, wie sich diese Art der expliziten Schnittstellenimplementierung von der "normalen" expliziten Schnittstellenimplementierung unterscheidet, würde ich mich gerne weiter damit befassen.
Alte Antwort zur expliziten Schnittstellenimplementierung
Trotz des oben Gesagten, das aufgrund der Kenntnis von Arrays komplizierter ist, können Sie durch explizite Schnittstellenimplementierung immer noch etwas mit denselben sichtbaren Effekten tun .
Hier ist ein einfaches eigenständiges Beispiel:
public interface IFoo
{
void M1();
void M2();
}
public class Foo : IFoo
{
// Explicit interface implementation
void IFoo.M1() {}
// Implicit interface implementation
public void M2() {}
}
class Test
{
static void Main()
{
Foo foo = new Foo();
foo.M1(); // Compile-time failure
foo.M2(); // Fine
IFoo ifoo = foo;
ifoo.M1(); // Fine
ifoo.M2(); // Fine
}
}
Array
Klasse müsse in C # geschrieben werden!