¿Cuál es la diferencia entre <out T>y <T>? Por ejemplo:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
¿Cuál es la diferencia entre <out T>y <T>? Por ejemplo:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Respuestas:
La outpalabra 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>. Como IEnumerable<out T>es covariante, puede hacer lo siguiente:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
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 que IEnumerable<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 que IList<T>tiene un Addmétodo. Supongamos que esto se permitiría:
IList<string> strings = new List<string>();
IList<object> objects = strings; // NOTE: Fails at compile time
Entonces puedes llamar:
objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object
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 concreto IComparer<Foo>directamente como IComparer<Bar>si Bares una subclase de Foo, porque la IComparer<in T>interfaz es contravariante .
Imagees una clase abstracta;) Puedes hacerlo new List<object>() { Image.FromFile("test.jpg") };sin problemas, o también puedes hacerlo new List<object>() { new Bitmap("test.jpg") };. El problema con el tuyo es que new Image()no está permitido (tampoco puedes hacerlo var img = new Image();)
IList<object>es un ejemplo extraño, si quieres objectno necesitas genéricos.
Para recordar fácilmente el uso de iny la outpalabra clave (también covarianza y contravarianza), podemos representar la herencia como envoltura:
String : Object
Bar : Foo

considerar,
class Fruit {}
class Banana : Fruit {}
interface ICovariantSkinned<out T> {}
interface ISkinned<T> {}
y las funciones,
void Peel(ISkinned<Fruit> skinned) { }
void Peel(ICovariantSkinned<Fruit> skinned) { }
La función que acepta ICovariantSkinned<Fruit>podrá aceptar ICovariantSkinned<Fruit>o ICovariantSkinned<Bananna>porque ICovariantSkinned<T>es una interfaz covariante y Bananaes un tipo de Fruit,
la función que acepta ISkinned<Fruit>solo podrá aceptar ISkinned<Fruit>.
" out T" significa que el tipo Tes "covariante". Eso limita Ta 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 de T.
Por ejemplo, ICovariant<out Dog>se puede echar a ICovariant<Animal>.
outejecuciones solo Tse pueden devolver, hasta que leí esta respuesta. ¡Todo el concepto tiene más sentido ahora!
Desde el enlace que publicaste ...
Para los parámetros de tipo genérico, la palabra clave out especifica que el parámetro de tipo es covariante .
EDITAR : nuevamente, desde el enlace que publicaste
Para obtener más información, vea Covarianza y contravarianza (C # y Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx