Nouvelle réponse à la lumière de la réponse de Hans
Grâce à la réponse donnée par Hans, nous pouvons voir que l'implémentation est un peu plus compliquée que ce que l'on pourrait croire. Le compilateur et le CLR essaient tous deux très difficile pour donner l'impression qu'un type de tableau implémente IList<T>
- mais la variance des tableaux rend la chose plus délicate. Contrairement à la réponse de Hans, les types de tableaux (unidimensionnels, basés sur des zéros) implémentent directement les collections génériques, parce que le type de tout tableau spécifique n'est pas System.Array
- c'est juste le base du tableau. Si vous demandez à un type de tableau quelles interfaces il supporte, il inclut les types génériques :
foreach (var type in typeof(int[]).GetInterfaces())
{
Console.WriteLine(type);
}
Sortie :
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]
Pour les tableaux unidimensionnels à base de zéro, dans la mesure où l'option langue le tableau implémente réellement IList<T>
aussi. La section 12.1.2 de la spécification C# le dit. Donc, quelle que soit l'implémentation sous-jacente, le langage doit se comporter comme si le type de T[]
met en œuvre IList<T>
comme pour toute autre interface. De ce point de vue, l'interface est mis en œuvre avec certains membres explicitement mis en œuvre (comme les Count
). C'est la meilleure explication à l'heure actuelle. langue pour ce qui se passe.
Notez que cela ne s'applique qu'aux tableaux unidimensionnels (et aux tableaux basés sur des zéros, bien que le langage C# ne dise rien au sujet des tableaux non basés sur des zéros). T[,]
n'a pas mettre en œuvre IList<T>
.
Du point de vue du CLR, il se passe quelque chose de plus funky. Vous ne pouvez pas obtenir le mappage d'interface pour les types d'interface génériques. Par exemple :
typeof(int[]).GetInterfaceMap(typeof(ICollection<int>))
Donne une exception de :
Unhandled Exception: System.ArgumentException: Interface maps for generic
interfaces on arrays cannot be retrived.
Alors pourquoi cette bizarrerie ? Eh bien, je crois que c'est dû à la covariance des tableaux, qui est une verrue dans le système de type, IMO. Même si IList<T>
es no covariante (et ne peut pas l'être en toute sécurité), la covariance des tableaux permet de fonctionner :
string[] strings = { "a", "b", "c" };
IList<object> objects = strings;
... ce qui en fait regardez como typeof(string[])
met en œuvre IList<object>
alors que ce n'est pas le cas.
La spécification CLI (ECMA-335) partition 1, section 8.7.1, contient ceci :
Un type de signature T est compatible avec un type de signature U si et seulement si au moins une des conditions suivantes est remplie
...
T est un tableau de rang 1 basé sur zéro V[]
y U
es IList<W>
et V est compatible avec W par élément de tableau.
(Il ne mentionne pas réellement ICollection<W>
o IEnumerable<W>
ce qui, je crois, est un bogue dans la spécification).
Pour la non-variance, la spécification CLI va directement de pair avec la spécification du langage. De la section 8.9.1 de la partition 1 :
De plus, un vecteur créé avec le type d'élément T, implémente l'interface System.Collections.Generic.IList<U>
où U := T. (§8.7)
(A vecteur est un tableau unidimensionnel avec une base zéro).
Maintenant, en termes de détails de mise en œuvre il est clair que le CLR effectue des mappings bizarres pour assurer la compatibilité des affectations : lorsqu'une fonction string[]
est demandé pour la mise en œuvre de ICollection<object>.Count
il ne peut pas gérer cela dans tout à fait de la manière habituelle. Est-ce que cela compte comme une implémentation explicite de l'interface ? Je pense qu'il est raisonnable de le traiter de cette façon, car à moins que vous ne demandiez directement le mappage de l'interface, il est toujours se comporte comme suit : d'un point de vue linguistique.
Qu'en est-il ICollection.Count
?
Jusqu'à présent, j'ai parlé des interfaces génériques, mais il existe aussi des interfaces non génériques. ICollection
avec son Count
propriété. Cette fois-ci, nous puede obtenir le mappage de l'interface, et en fait l'interface est directement implémentée par System.Array
. La documentation relative au ICollection.Count
dans l'implémentation de la propriété Array
indique qu'elle est implémentée avec une interface explicite.
Si quelqu'un a une idée de la manière dont ce type d'implémentation d'interface explicite est différent de l'implémentation d'interface explicite "normale", je serais heureux de l'examiner plus avant.
Ancienne réponse concernant l'implémentation explicite d'une interface
Malgré ce qui précède, qui est plus compliqué en raison de la connaissance des tableaux, vous pouvez toujours faire quelque chose avec le même visible effets par mise en œuvre explicite de l'interface .
Voici un exemple simple et autonome :
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
}
}