Qual é a diferença entre <out T>e <T>? Por exemplo:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Qual é a diferença entre <out T>e <T>? Por exemplo:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Respostas:
A outpalavra-chave em genéricos é usada para indicar que o tipo T na interface é covariante. Consulte Covariância e contravariância para obter detalhes.
O exemplo clássico é IEnumerable<out T>. Como IEnumerable<out T>é covariante, você pode fazer o seguinte:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
A segunda linha acima falharia se isso não fosse covariante, mesmo que logicamente funcione, pois a string deriva do objeto. Antes de a variação nas interfaces genéricas ser adicionada ao C # e ao VB.NET (no .NET 4 com VS 2010), era um erro de tempo de compilação.
Após o .NET 4, IEnumerable<T>foi marcado covariante e tornou-se IEnumerable<out T>. Como IEnumerable<out T>apenas usa os elementos contidos nele e nunca os adiciona / altera, é seguro tratar uma coleção enumerável de strings como uma coleção enumerável de objetos, o que significa que é covariante .
Isso não funcionaria com um tipo como IList<T>, pois IList<T>possui um Addmétodo Suponha que isso seja permitido:
IList<string> strings = new List<string>();
IList<object> objects = strings; // NOTE: Fails at compile time
Você pode ligar para:
objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object
Obviamente, isso falharia - portanto, IList<T>não pode ser marcado como covariante.
Também existe uma opção para in- que é usada por coisas como interfaces de comparação. IComparer<in T>, por exemplo, funciona da maneira oposta. Você pode usar um concreto IComparer<Foo>diretamente como um IComparer<Bar>if Baré uma subclasse de Foo, porque a IComparer<in T>interface é contravariante .
Imageé uma classe abstrata;) Você pode fazer new List<object>() { Image.FromFile("test.jpg") };sem problemas ou new List<object>() { new Bitmap("test.jpg") };também. O problema com o seu é que new Image()não é permitido (você não pode fazer var img = new Image();qualquer um)
IList<object>é um exemplo bizarro, se você deseja objects, não precisa de genéricos.
Para lembrar facilmente o uso ine a outpalavra - chave (também covariância e contravariância), podemos imaginar a herança como quebra automática:
String : Object
Bar : Foo

considerar,
class Fruit {}
class Banana : Fruit {}
interface ICovariantSkinned<out T> {}
interface ISkinned<T> {}
e as funções,
void Peel(ISkinned<Fruit> skinned) { }
void Peel(ICovariantSkinned<Fruit> skinned) { }
A função que aceita ICovariantSkinned<Fruit>poderá aceitar ICovariantSkinned<Fruit>ou ICovariantSkinned<Bananna>porque ICovariantSkinned<T>é uma interface covariante e Bananaé um tipo deFruit ,
a função que aceita ISkinned<Fruit>somente poderá aceitar ISkinned<Fruit>.
" out T" significa que o tipo Té "covariante". Isso restringe Ta aparecer apenas como um valor retornado (de saída) nos métodos da classe, interface ou método genérico. A implicação é que você pode converter o tipo / interface / método em um equivalente com um supertipo de T.
Por exemplo, ICovariant<out Dog>pode ser lançado para ICovariant<Animal>.
outreforças que Tpodem ser retornadas apenas, até que eu li esta resposta. Todo o conceito faz mais sentido agora!
No link que você postou ....
Para parâmetros de tipo genérico, a palavra-chave out especifica que o parâmetro type é covariante .
EDIT : novamente, a partir do link que você postou
Para obter mais informações, consulte Covariância e contravariância (C # e Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx