43 Stimmen

Kovarianter allgemeiner Parameter

Ich versuche, das zu verstehen, aber ich habe bei der Suche keine geeigneten Ergebnisse gefunden.

In C# 4 kann ich Folgendes tun

    public interface IFoo<out T>
    {

    }

Was ist der Unterschied zu

    public interface IFoo<T>
    {

    }

Ich weiß nur, dass die out macht den generischen Parameter kovariant (??). Kann mir jemand die Verwendung von <out T> Teil mit einem Beispiel? Und warum gilt das nur für Schnittstellen und Delegierte und nicht für Klassen?

Es tut mir leid, wenn es ein Duplikat ist und schließe es als solches, wenn es eines ist.

53voto

Eric Lippert Punkte 628543

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/

8voto

Tomasz Jaskuλa Punkte 15373

Wenn wir von allgemeiner Varianz sprechen:

Kovarianz geht es um Werte, die von einer Operation an den Aufrufer zurückgegeben werden.

Kontravarianz Das Gegenteil ist der Fall, und es geht um Werte, die vom Aufrufer übergeben werden:

Soweit ich weiß, können Sie out verwenden, wenn ein Typparameter nur für die Ausgabe verwendet wird. Wenn der Typ jedoch nur für die Eingabe verwendet wird, können Sie in verwenden. Das ist praktisch, weil der Compiler nicht sicher sein kann, ob Sie sich merken können, welche Form Kovarianz und welche Kontravarianz heißt. Wenn Sie sie nicht explizit deklarieren, sobald der Typ deklariert wurde, stehen die entsprechenden Konvertierungstypen zur Verfügung implizit .

Es gibt keine Varianz (weder Kovarianz noch Kontravarianz) in Klassen, denn selbst wenn Sie eine Klasse haben, die den Typparameter nur für die Eingabe (oder nur für die Ausgabe) verwendet, müssen Sie kann man die Modifikatoren in oder out nicht angeben. Nur Schnittstellen und Delegaten können variante Typparameter haben. Erstens lässt die CLR dies nicht zu. Vom konzeptionellen Standpunkt aus gesehen stellen Schnittstellen eine Möglichkeit dar, ein Objekt aus einer bestimmten Perspektive zu betrachten, während Klassen eher konkrete Umsetzung Typen.

7voto

recursive Punkte 80517

Das heißt, wenn Sie das haben:

class Parent { } 
class Child : Parent { }

Dann wird eine Instanz von IFoo<Child> ist auch eine Instanz von IFoo<Parent> .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X