Kann jemand die Verwendung des Teils "out T" anhand eines Beispiels erklären?
Ja, sicher. IEnumerable<T>
ist kovariant. Das bedeutet, dass Sie dies tun können:
static void FeedAll(IEnumerable<Animal> animals)
{
foreach(Animal animal in animals) animal.Feed();
}
...
IEnumerable<Giraffe> giraffes = GetABunchOfGiraffes();
FeedAll(giraffes);
"Kovariant" bedeutet, dass die Zuweisungskompatibilitätsbeziehung des Typarguments im generischen Typ erhalten bleibt . Giraffe
ist die Zuordnung kompatibel mit Animal
und daher wird diese Beziehung in den konstruierten Typen beibehalten: IEnumerable<Giraffe>
ist die Zuordnung kompatibel mit IEnumerable<Animal>
.
Warum gilt das nur für Schnittstellen und Delegierte und nicht für Klassen?
Das Problem mit Klassen besteht darin, dass Klassen in der Regel veränderbare Felder haben. Nehmen wir ein Beispiel. Nehmen wir an, wir haben dies erlaubt:
class C<out T>
{
private T t;
Nun gut, denken Sie gut über diese Frage nach, bevor Sie fortfahren. Dose C<T>
eine Methode außerhalb des Konstruktors haben, die das Feld t
auf etwas anderes als die Standardeinstellung?
Weil es typensicher sein muss, C<T>
kann nun keine Methoden haben, die ein T als Argument annehmen; T kann nur zurückgegeben werden. Wer setzt also t, und Woher nehmen sie den Wert, den sie festlegen? ?
Kovariante Klassentypen funktionieren wirklich nur, wenn die Klasse unveränderlich . Und wir haben keine gute Möglichkeit, unveränderliche Klassen in C# zu erstellen.
Ich wünschte, es wäre so, aber wir müssen mit dem CLR-System leben, das uns zur Verfügung gestellt wurde. Ich hoffe, dass wir in Zukunft eine bessere Unterstützung für unveränderliche Klassen und für kovariante Klassen haben werden.
Wenn Sie sich für diese Funktion interessieren, sollten Sie meine lange Serie darüber lesen, wie wir diese Funktion entwickelt und implementiert haben. Beginnen Sie von unten:
https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/