Nuova risposta alla luce della risposta di Hans
Grazie alla risposta data da Hans, possiamo vedere che l'implementazione è un po 'più complicata di quanto potremmo pensare. Sia il compilatore e il CLR prova molto duro per dare l'impressione che un tipo di matrice attrezzi IList<T>- ma varianza gamma rende questo più complicato. Contrariamente alla risposta di Hans, i tipi di matrice (unidimensionale, in ogni caso a base zero) implementano direttamente le raccolte generiche, perché il tipo di un array specifico non lo è System.Array , è solo il tipo di base dell'array. Se chiedi a un tipo di array quali interfacce supporta, include i tipi generici:
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Produzione:
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]
Per array monodimensionali a base zero, per quanto riguarda il linguaggio , anche l'array implementa IList<T>davvero. La sezione 12.1.2 della specifica C # lo dice. Quindi, qualunque sia l'implementazione sottostante, il linguaggio deve comportarsi come se il tipo di T[]implementa IList<T>come con qualsiasi altra interfaccia. Da questo punto di vista, l'interfaccia è implementata con alcuni dei membri che vengono implementati esplicitamente (come Count). Questa è la migliore spiegazione a livello di lingua per quello che sta succedendo.
Si noti che questo vale solo per gli array unidimensionali (e gli array a base zero, non che il linguaggio C # dica qualcosa sugli array non a base zero). T[,] non implementa IList<T>.
Dal punto di vista di CLR, sta succedendo qualcosa di più funky. Non è possibile ottenere la mappatura dell'interfaccia per i tipi di interfaccia generici. Per esempio:
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Dà un'eccezione di:
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
Allora perché la stranezza? Bene, credo che sia davvero dovuto alla covarianza degli array, che è una verruca nel sistema dei tipi, IMO. Anche se nonIList<T> è covariante (e non può essere sicuro), la covarianza dell'array consente a questo di funzionare:
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... il che lo fa sembrare un typeof(string[])attrezzo IList<object>, quando in realtà non lo è.
La partizione 1 delle specifiche CLI (ECMA-335), sezione 8.7.1, ha questo:
Un tipo di firma T è compatibile con un tipo di firma U se e solo se almeno una delle seguenti condizioni è valida
...
T è un array di rango 1 a base zero V[], ed Uè IList<W>, e V è compatibile con l'elemento dell'array W.
(In realtà non menziona ICollection<W>o IEnumerable<W>che credo sia un bug nelle specifiche.)
Per non varianza, la specifica CLI va di pari passo con la specifica della lingua. Dalla sezione 8.9.1 della partizione 1:
Inoltre, un vettore creato con il tipo di elemento T, implementa l'interfaccia System.Collections.Generic.IList<U>, dove U: = T. (§8.7)
(Un vettore è un array unidimensionale con una base zero.)
Ora, in termini di dettagli di implementazione , chiaramente il CLR sta facendo un po 'di mappatura funky per mantenere la compatibilità dell'assegnazione qui: quando a string[]viene richiesta l'implementazione di ICollection<object>.Count, non può gestirlo in modo abbastanza normale. Questo conta come implementazione esplicita dell'interfaccia? Penso che sia ragionevole trattarlo in questo modo, poiché a meno che tu non chieda direttamente la mappatura dell'interfaccia, si comporta sempre in quel modo dal punto di vista del linguaggio.
Di cosa ICollection.Count?
Finora ho parlato delle interfacce generiche, ma poi c'è il non generico ICollectioncon la sua Countproprietà. Questa volta siamo in grado di ottenere la mappatura di interfaccia, e in effetti l'interfaccia è implementata direttamente System.Array. La documentazione per l' ICollection.Countimplementazione della proprietà Arrayafferma che è implementata con l'implementazione dell'interfaccia esplicita.
Se qualcuno può pensare a un modo in cui questo tipo di implementazione esplicita dell'interfaccia è diverso dalla "normale" implementazione esplicita dell'interfaccia, sarei felice di esaminarlo ulteriormente.
Vecchia risposta sull'implementazione dell'interfaccia esplicita
Nonostante quanto sopra, che è più complicato a causa della conoscenza degli array, puoi ancora fare qualcosa con gli stessi effetti visibili attraverso l' implementazione dell'interfaccia esplicita .
Ecco un semplice esempio autonomo:
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
}
}
Arrayclasse doveva essere scritta in C #!