¿Cuál es la diferencia entre <out T>
y <T>
? Por ejemplo:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
c#
generics
covariance
Cole Johnson
fuente
fuente
Respuestas:
La
out
palabra clave en genéricos se usa para denotar que el tipo T en la interfaz es covariante. Ver Covarianza y contravarianza para más detalles.El ejemplo clásico es
IEnumerable<out T>
. ComoIEnumerable<out T>
es covariante, puede hacer lo siguiente:La segunda línea anterior fallaría si esto no fuera covariante, aunque lógicamente debería funcionar, ya que la cadena deriva del objeto. Antes de que se agregaran variaciones en las interfaces genéricas a C # y VB.NET (en .NET 4 con VS 2010), esto fue un error de tiempo de compilación.
Después de .NET 4,
IEnumerable<T>
se marcó covariante y se convirtióIEnumerable<out T>
. Dado queIEnumerable<out T>
solo usa los elementos que contiene y nunca los agrega / cambia, es seguro que trate una colección enumerable de cadenas como una colección enumerable de objetos, lo que significa que es covariante .Esto no funcionaría con un tipo como
IList<T>
, ya queIList<T>
tiene unAdd
método. Supongamos que esto se permitiría:Entonces puedes llamar:
Esto, por supuesto, fallaría, por
IList<T>
lo que no se puede marcar como covariante.También hay, por cierto, una opción para
in
, que es utilizada por cosas como interfaces de comparación.IComparer<in T>
, por ejemplo, funciona de manera opuesta. Puede usar un concretoIComparer<Foo>
directamente comoIComparer<Bar>
siBar
es una subclase deFoo
, porque laIComparer<in T>
interfaz es contravariante .fuente
Image
es una clase abstracta;) Puedes hacerlonew List<object>() { Image.FromFile("test.jpg") };
sin problemas, o también puedes hacerlonew List<object>() { new Bitmap("test.jpg") };
. El problema con el tuyo es quenew Image()
no está permitido (tampoco puedes hacerlovar img = new Image();
)IList<object>
es un ejemplo extraño, si quieresobject
no necesitas genéricos.Para recordar fácilmente el uso de
in
y laout
palabra clave (también covarianza y contravarianza), podemos representar la herencia como envoltura:fuente
considerar,
y las funciones,
La función que acepta
ICovariantSkinned<Fruit>
podrá aceptarICovariantSkinned<Fruit>
oICovariantSkinned<Bananna>
porqueICovariantSkinned<T>
es una interfaz covariante yBanana
es un tipo deFruit
,la función que acepta
ISkinned<Fruit>
solo podrá aceptarISkinned<Fruit>
.fuente
"
out T
" significa que el tipoT
es "covariante". Eso limitaT
a aparecer solo como un valor devuelto (saliente) en los métodos de la clase genérica, interfaz o método. La implicación es que puede convertir el tipo / interfaz / método a un equivalente con un supertipo deT
.Por ejemplo,
ICovariant<out Dog>
se puede echar aICovariant<Animal>
.fuente
out
ejecuciones soloT
se pueden devolver, hasta que leí esta respuesta. ¡Todo el concepto tiene más sentido ahora!Desde el enlace que publicaste ...
EDITAR : nuevamente, desde el enlace que publicaste
fuente