usar una que puede programacion porque interfaz interfaces instancia implementacion heredar declaracion declara cómo crear clase caracteristicas c# c#-4.0 ienumerable covariance

c# - una - ¿Por qué las clases que implementan interfaces variantes permanecen invariables?



que es una interfaz en programacion (2)

En primer lugar, las clases siempre son invariables en C #. No puedes declarar una clase como esta:

// Invalid public class Foo<out T>

En segundo lugar, y más importante para el ejemplo que ha dado, List<T> no se pudo declarar como covariante o contravariante en T todos modos, ya que tiene miembros que aceptan y devuelven valores de tipo T

Imagina si fuera covariante. Entonces podrías escribir esto (para la jerarquía obvia de la clase Fruit ):

List<Banana> bunchOfBananas = new List<Banana>(); // This would be valid if List<T> were covariant in T List<Fruit> fruitBowl = bunchOfBananas; fruitBowl.Add(new Apple()); Banana banana = bunchOfBananas[0];

¿Qué esperarías que hiciera esa última línea? Fundamentalmente, no debería poder agregar una referencia de Apple a un objeto cuyo tipo de tiempo de ejecución real sea List<Banana> . Si agrega una manzana a un manojo de plátanos, se cae. Créame, lo he intentado.

La última línea debería ser segura en términos de tipos: los únicos valores dentro de una List<Banana> deberían ser null o las referencias a instancias de Banana o una subclase.

Ahora, en cuanto a por qué las clases no pueden ser covariantes incluso cuando podrían ser lógicamente ... Creo que eso introduce problemas a nivel de implementación, y también sería muy restrictivo a nivel de programación. Por ejemplo, considera esto:

public class Foo<out T> // Imagine if this were valid { private T value; public T Value { get { return value; } } public Foo(T value) { this.value = value; } }

Probablemente aún tenga que ser inválido: la variable aún se puede escribir, lo que significa que cuenta como un espacio "en". Tendría que hacer todas las variables de tipo T de solo lectura ... y eso es solo para empezar. Sospecho fuertemente que habría problemas más profundos.

En términos de pragmatismo puro, el CLR ha soportado delegado y la varianza de interfaz de v2 - C # 4 acaba de introducir la sintaxis para exponer la característica. No creo que el CLR alguna vez haya respaldado la varianza genérica de clase.

C # 4.0 ha ampliado aún más la co y la contravariación para los tipos e interfaces genéricos. Algunas interfaces (como IEnumerable<T> ) son covariantes, por lo que puedo hacer cosas como:

IEnumerable<object> ie = new List<string>();

pero ¿qué pasa con esta línea? Tengo un error en tiempo de compilación

List<Object> list = new List<String>(); //Cannot implicitly convert type List<string>'' to List<object>''

Quiero decir, si List<T> implementa IEnumerable<T> ¿por qué List<T> sigue siendo invariante? ¿Existe un buen contraejemplo que explique por qué esto no debe permitirse en C #?


Si queremos discutir agregar (aceptar) algo (T) a la Lista, debemos hablar sobre CONTRARANTIA (COVARIANZA no permite aceptar), entonces:

List<Fruit> bunchOfFruits = new List<Fruit>(); // This would be valid if List<T> were contravariant in T List<Banana> bunchOfBananas = bunchOfFruits; bunchOfBananas.Add(new Apple()); // not possible! We have compile error, coz in spite of Apple is a Fruit it is not ancestor of Banana. No logical mistakes. bunchOfBananas.Add(new BigBanana()); // possible coz of rules of C#! we deal with a descendant of Banana bunchOfBananas.Add(new Fruit()); // possible, coz CONTRAVARIANCE of List. We deal with the ancestor of Banana. No logical mistakes.

Entonces, como podemos ver, VARIANCE debería funcionar tanto para las clases como para las interfaces y los delegados (clases en general, no solo para colecciones). Y creo que se puede implementar en versiones futuras de .NET.