Mise à JOUR: Cette question a été la base de mon entrée de blog pour le lundi 4 avril 2011. Merci pour la grande question.
Permettez-moi de le décomposer en plusieurs petites questions.
N' List<T>
vraiment mettre en œuvre toutes ces interfaces?
Oui.
Pourquoi?
Parce que quand une interface (par exemple, IList<T>
) hérite d'une interface (disons IEnumerable<T>
) puis la mise en œuvre de la plus dérivée de l'interface sont nécessaires pour mettre en œuvre la moins dérivé de l'interface. C'est ce que l'héritage de l'interface moyens; si vous remplissez le contrat de la plus type dérivé ensuite, vous devez également remplir le contrat de moins de type dérivé.
Si une classe doit implémenter toutes les méthodes de toutes les interfaces dans la fermeture transitive de ses interfaces de base?
Exactement.
Est une classe qui implémente une interface dérivée également tenu d'indiquer dans son type de base de la liste que c'est la mise en œuvre de l'ensemble de ceux qui sont moins dérivées des interfaces?
Pas de.
C'est la classe doivent PAS état?
Pas de.
Il est donc facultatif si la moins-dérivée de la mise en œuvre des interfaces sont indiquées dans le type de base de la liste?
Oui.
Toujours?
Presque toujours:
interface I1 {}
interface I2 : I1 {}
interface I3 : I2 {}
Elle est facultative si I3 états qu'il hérite de I1.
class B : I3 {}
La mise en œuvre de I3 sont nécessaires pour mettre en œuvre I2 et I1, mais ils ne sont pas tenus d'indiquer explicitement qu'ils le font. C'est facultatif.
class D : B {}
Les classes dérivées ne sont pas nécessaires à la re-état de la mise en œuvre d'une interface à partir de leur classe de base, mais sont autorisés à le faire. (Ce cas est spécial; voir ci-dessous pour plus de détails.)
class C<T> where T : I3
{
public virtual void M<U>() where U : I3 {}
}
Les arguments de Type correspondant à T et U sont nécessaires pour mettre en œuvre I2 et I1, mais elle est facultative pour les contraintes sur T ou U pour l'état.
Il est toujours l'option de re-état de base de l'interface dans une classe partielle:
partial class E : I3 {}
partial class E {}
La seconde moitié de E est autorisé à déclarer qu'il met en œuvre I3 et I2 ou I1, mais pas obligé de le faire.
OK, je l'obtenir; il est facultatif. Pourquoi quelqu'un inutilement de l'état d'une interface de base?
Peut-être parce qu'ils croient que cela rend le code plus facile à comprendre et plus l'auto-documentation.
Ou, peut-être le développeur écrit le code
interface I1 {}
interface I2 {}
interface I3 : I1, I2 {}
et le réalisé, oh, attendez une minute, I2 devrait hériter de I1. Pourquoi devrait faire que modifier, puis exiger que le promoteur de revenir en arrière et modifier la déclaration de I3 à ne pas contenir la mention explicite de I1? Je ne vois aucune raison de forcer les développeurs à supprimer les informations redondantes.
En plus d'être plus facile à lire et à comprendre, est-il une technique différence entre indiquant une interface explicitement dans le type de base de la liste et de le laisser sous silence mais implicite?
Généralement non, mais il peut y avoir une différence subtile dans un cas. Supposons que vous avez une classe dérivée de D dont la classe de base B a mis en œuvre certaines interfaces. D implémente automatiquement les interfaces via B. Si vous re-état des interfaces en D pour la classe de base de la liste puis le compilateur C# va faire une interface de mise en œuvre. Les détails sont un peu subtile; si vous êtes intéressé par la façon dont cela fonctionne, alors je vous recommande une lecture attentive de l'article 13.4.6 du C# 4 spécification.
L' List<T>
code source fait état de toutes les interfaces?
Pas de. Le code source dit
public class List<T> : IList<T>, System.Collections.IList
Pourquoi ne MSDN avoir l'interface complète de la liste, mais le vrai code source ne l'est pas?
MSDN est de la documentation; il est censé vous donner autant d'informations que vous pourriez vouloir. Il est beaucoup plus clair pour que la documentation soit complète en une seule place que de faire de la recherche à travers une dizaine de pages pour trouver ce que l'interface de jeu est.
Pourquoi ne Réflecteur afficher toute la liste?
Réflecteur a seulement des métadonnées à partir de ce point. Depuis la mise en la liste complète est facultatif, Réflecteur n'a aucune idée de savoir si le code source d'origine contient la liste complète ou pas. Il est préférable de pécher par excès de plus d'informations. Encore une fois, le Réflecteur est de tenter de vous aider en vous montrant plus d'informations plutôt que de cacher les informations dont vous pourriez avoir besoin.
QUESTION BONUS: Pourquoi est - IEnumerable<T>
hériter d' IEnumerable
mais IList<T>
n'hérite pas de IList
?
Une séquence d'entiers peut être traitée comme une séquence d'objets, par la boxe tout entier qu'il sort de la séquence. Mais une lecture-écriture de la liste d'entiers ne peut être traitée comme un lire-écrire la liste des objets, parce que vous pouvez mettre une chaîne en lecture-écriture à la liste des objets. Un IList<T>
n'est pas tenu de s'acquitter de l'ensemble du contrat d' IList
, de sorte qu'il n'hérite pas de lui.