ACTUALIZACIÓN: Esta pregunta fue la base de my blog entry for Monday April 4th 2011. Gracias por la gran pregunta.
Déjenme desglosarlo en muchas preguntas más pequeñas.
¿Realmente implementa List<T>
todas esas interfaces?
Sí.
¿Por qué?
Porque cuando una interfaz (por ejemplo, IList<T>
) hereda de una interfaz (por ejemplo IEnumerable<T>
) entonces se requieren ejecutores de la interfaz más derivado para también implementar la interfaz menos derivada. Eso es lo que significa herencia de interfaz; si cumple el contrato del tipo más derivado, se le exige que también cumpla el contrato del tipo menos derivado.
Entonces, ¿se requiere una clase para implementar todos los métodos de todas las interfaces en el cierre transitivo de sus interfaces base?
Exactamente.
¿Es una clase que implementa una interfaz más derivada también necesaria para indicar en su lista de tipos básicos que está implementando todas esas interfaces menos derivadas?
Nº
es la clase requerida para indicar que NO?
Nº
Así que es opcional si las interfaces implementadas menos derivados se indican en la lista de tipos de base?
Sí.
¿Siempre?
Casi siempre:
interface I1 {}
interface I2 : I1 {}
interface I3 : I2 {}
Es opcional si I3 afirma que hereda de I1.
class B : I3 {}
implementadores de I3 están obligados a poner en práctica I2 e I1, pero no están obligados a declarar explícitamente que lo están haciendo. Es opcional
class D : B {}
Las clases derivadas no están obligados a volver a exponer que implementan una interfaz de su clase base, pero se les permite hacerlo. (Este caso es especial; ver más abajo para más detalles).
class C<T> where T : I3
{
public virtual void M<U>() where U : I3 {}
}
argumentos de tipo correspondiente a T y T son necesarios para implementar I2 e I1, pero es opcional para las restricciones en T o T para afirmar que.
Siempre es opcional para volver a exponer cualquier interfaz de base en una clase parcial:
partial class E : I3 {}
partial class E {}
está permitida la segunda mitad de E para indicar que implementa I3 o I2 o I1, pero no es necesario hacer asi que.
OK, lo entiendo; es opcional ¿Por qué alguien declararía innecesariamente una interfaz base?
Tal vez porque creen que hacerlo hace que el código sea más fácil de entender y más autodocumentado.
O, tal vez el desarrollador ha escrito el código como
interface I1 {}
interface I2 {}
interface I3 : I1, I2 {}
y se dio cuenta, oh, espera un minuto, I2 debe heredar de I1.¿Por qué hacer esa edición requiere que el desarrollador regrese y cambie la declaración de I3 a no que contenga mención explícita de I1? No veo ninguna razón para obligar a los desarrolladores a eliminar la información redundante.
Aparte de ser más fácil de leer y entender, ¿hay alguna diferencia técnica entre indicando una interfaz explícitamente en la lista tipo de base y dejándolo sin especificar pero implícita?
Normalmente no, pero puede haber una diferencia sutil en un caso. Supongamos que tiene una clase derivada D cuya clase base B ha implementado algunas interfaces. D implementa automáticamente esas interfaces a través de B. Si vuelve a establecer las interfaces en la lista de clases base de D, el compilador de C# realizará una nueva implementación de la interfaz . Los detalles son un poco sutiles; Si le interesa cómo funciona esto, le recomiendo una lectura cuidadosa de la sección 13.4.6 de la especificación C# 4.
¿El código fuente List<T>
en realidad indica todas esas interfaces?
No. El código fuente real dice
public class List<T> : IList<T>, System.Collections.IList
¿Por qué MSDN tienen la lista completa de interfaz pero el código fuente real no?
Porque MSDN es la documentación; se supone que debe darle tanta información como desee. Es mucho más claro que la documentación esté completa en un solo lugar que hacer que busque entre diez páginas diferentes para descubrir cuál es el conjunto de interfaz completo.
¿Por qué Reflector muestra toda la lista?
Reflector solo tiene metadatos para trabajar. Como poner en la lista completa es opcional, Reflector no tiene idea de si el código fuente original contiene la lista completa o no. Es mejor equivocarse al lado de más información. Una vez más, Reflector intenta ayudarlo mostrándole más información en lugar de ocultar la información que pueda necesitar.
PRIMA PREGUNTA: ¿Por qué IEnumerable<T>
Heredar del IEnumerable
pero IList<T>
no hereda de IList
?
Una secuencia de enteros se puede tratar como una secuencia de objetos, encajonando cada entero como sale de la secuencia. Pero una lista de lectura y escritura de enteros no puede tratarse como una lista de objetos de lectura y escritura, porque puede poner una cadena en una lista de objetos de lectura y escritura. No es necesario un IList<T>
para cumplir con el contrato completo de IList
, por lo que no hereda de él.
Sí La lista implementa todas esas interfaces, ¿por qué ?, porque todas son relevantes para una colección de listas. ¿Para qué es tu código? ¿Es esa una pregunta diferente? –
Su código de ejemplo no tiene nada que ver con la clase '' Lista ... –
BoltClock
creo que está preguntando por qué 'Lista pública de clase: IList , ICollection , IEnumerable , etc.' en lugar de simplemente' Lista public class : IList '. Tenga en cuenta que 'ICollection' y' IList' (los no genéricos) no se heredan de 'IList '. –
Rup