Qual è la differenza tra <out T>e <T>? Per esempio:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Qual è la differenza tra <out T>e <T>? Per esempio:
public interface IExample<out T>
{
...
}
vs.
public interface IExample<T>
{
...
}
Risposte:
La outparola chiave in generici viene utilizzata per indicare che il tipo T nell'interfaccia è covariante. Vedi Covarianza e contraddizione per i dettagli.
L'esempio classico è IEnumerable<out T>. Poiché IEnumerable<out T>è covariante, è consentito eseguire le seguenti operazioni:
IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;
La seconda riga sopra fallirebbe se ciò non fosse covariante, anche se logicamente dovrebbe funzionare, poiché la stringa deriva dall'oggetto. Prima che la varianza delle interfacce generiche fosse aggiunta a C # e VB.NET (in .NET 4 con VS 2010), si trattava di un errore di compilazione.
Dopo .NET 4, è IEnumerable<T>stato contrassegnato come covariante ed è diventato IEnumerable<out T>. Dal momento IEnumerable<out T>che utilizza solo gli elementi al suo interno e non li aggiunge / modifica mai, è sicuro che tratti una collezione enumerabile di stringhe come una collezione enumerabile di oggetti, il che significa che è covariante .
Questo non funzionerebbe con un tipo come IList<T>, poiché IList<T>ha un Addmetodo. Supponiamo che ciò sia consentito:
IList<string> strings = new List<string>();
IList<object> objects = strings; // NOTE: Fails at compile time
È quindi possibile chiamare:
objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object
Ciò ovviamente fallirebbe, quindi IList<T>non può essere contrassegnato come covariante.
C'è anche, tra l'altro, un'opzione per in- che viene utilizzata da cose come interfacce di confronto. IComparer<in T>, ad esempio, funziona in modo opposto. Puoi usare un calcestruzzo IComparer<Foo>direttamente come IComparer<Bar>se Barè una sottoclasse di Foo, perché l' IComparer<in T>interfaccia è contraddittoria .
Imageè una classe astratta;) Puoi fare new List<object>() { Image.FromFile("test.jpg") };senza problemi, oppure puoi fare new List<object>() { new Bitmap("test.jpg") };altrettanto. Il problema con il tuo è che new Image()non è permesso (neanche tu puoi farlo var img = new Image();)
IList<object>è un bizzarro esempio, se vuoi objects non hai bisogno di generici.
Per ricordare facilmente l'uso ine la outparola chiave (anche covarianza e contraddizione), possiamo immaginare l'ereditarietà come wrapping:
String : Object
Bar : Foo

tener conto di,
class Fruit {}
class Banana : Fruit {}
interface ICovariantSkinned<out T> {}
interface ISkinned<T> {}
e le funzioni,
void Peel(ISkinned<Fruit> skinned) { }
void Peel(ICovariantSkinned<Fruit> skinned) { }
La funzione che accetta ICovariantSkinned<Fruit>sarà in grado di accettare ICovariantSkinned<Fruit>o ICovariantSkinned<Bananna>perchéICovariantSkinned<T> è un'interfaccia covariante ed Bananaè un tipo diFruit ,
la funzione che accetta ISkinned<Fruit>sarà solo in grado di accettare ISkinned<Fruit>.
" out T" significa che il tipo Tè "covariante". Ciò limita la Tvisualizzazione solo come valore restituito (in uscita) nei metodi della classe, interfaccia o metodo generici. L'implicazione è che puoi lanciare il tipo / interfaccia / metodo in un equivalente con un super-tipo di T.
Ad esempio ICovariant<out Dog>può essere lanciato ICovariant<Animal>.
outforze Tpossono essere restituite solo fino a quando non leggo questa risposta. L'intero concetto ha più senso ora!
Dal link che hai pubblicato ....
Per i parametri di tipo generico, la parola chiave out specifica che il parametro type è covariante .
EDIT : Ancora una volta, dal link che hai pubblicato
Per ulteriori informazioni, vedere Covarianza e contraddizione (C # e Visual Basic). http://msdn.microsoft.com/en-us/library/ee207183.aspx