Delegierte Kovarianz Verwirrung Conundrum!

7

Warum funktioniert das nicht? Kann ich Delegatkovarianz nicht richtig verstehen?

%Vor%     
Adam Driscoll 26.02.2010, 21:00
quelle

6 Antworten

12

Richtig - du verstehst Kovarianz nicht richtig - noch :) Dein Code würde funktionieren, wenn du die gleichen Typen aber wie return Werte hättest:

%Vor%

Das würde Kovarianz demonstrieren. Alternativ können Sie es als Parameter beibehalten, aber die Typen umschalten:

%Vor%

Dies zeigt jetzt Kontravarianz .

Meine Faustregel ist, sich selbst zu fragen: "Was kann ich mit dem Delegaten tun? Wenn ich ein Argument einbringen kann, das die Methode durchbricht, sollte die Konvertierung fehlgeschlagen sein. Wenn die Methode etwas zurückgeben kann, was würde den Aufrufer brechen, sollte die Konvertierung fehlgeschlagen sein. "

In Ihrem Code hätten Sie Folgendes aufrufen können:

%Vor%

An diesem Punkt hat der arme MyMethod einen Parameter, der bedeutet vom Typ SomeObject , aber tatsächlich vom Typ object ist. Dies wäre ein sehr schlechtes Ding, so dass der Compiler das verhindert.

Macht das alles mehr Sinn?

    
Jon Skeet 26.02.2010, 21:05
quelle
4

Sie müssen ein generisches verwenden.

  

EDIT: Warum? Weil als ein anderes Plakat   Beachten Sie, Objekt und SomeObject nicht   Gleiches wie das Objekt may   nicht SomeObject sein. Das ist das Ganze   Punkt der Generika in der Sprache.

%Vor%     
Payton Byrd 26.02.2010 21:05
quelle
4

Argumente sind kontravariant, Rückgabetypen sind kovariant. Wenn der Delegat mit einem object aufgerufen werden soll, das keine Instanz von SomeObject ist, haben Sie einen Tippfehler. Wenn andererseits SomeObject von einer Routine zurückgegeben wird, die in einen Delegaten eingeschlossen ist, der object zurückgibt, ist das in Ordnung.

    
Jeffrey Hantin 26.02.2010 21:06
quelle
1

Der MyDelegate -Typ deklariert, dass Sie jede Art von Objekt übergeben können. MyMethod nimmt jedoch nur Objekte vom Typ SomeObject . Was passiert, wenn ich versuche, den Delegaten aufzurufen, der eine andere Art von Objekt übergibt: _delegate("a string object") ? Gemäß der Deklaration von MyDelegate sollte dies erlaubt sein, aber Ihre Funktion MyMethod kann tatsächlich kein String-Argument erhalten.

    
JSBձոգչ 26.02.2010 21:05
quelle
1

Vom MSDN Link, den Sie zur Verfügung gestellt haben

  

Kovarianz erlaubt einer Methode, a zu haben    abgeleiteter Rückgabetyp als was ist   im Delegierten definiert.   Kontravarianz erlaubt eine Methode mit    Parametertypen, die weniger abgeleitet sind   als im Delegattyp.

Sie versuchen, einen abgeleiteten -Parametertyp zu verwenden, der nicht unterstützt wird (obwohl .NET 4.0 dies wahrscheinlich tun wird, da dies viele Kovarianz- / Kontravarianzprobleme aussortiert hat).

    
Paolo 26.02.2010 21:08
quelle
0

Bei Kovarianz und Kontravarianz geht es darum, das Is-a-Prinzip der Vererbung zu verstehen.

In beiden, Kovarianz und Kontravarianz, s. wird entweder als Rückgabewert oder als Argument für die Delegate-Methode übergeben. Was "weitergegeben" wird, muss in einem Gefäß "gefangen" werden. In C # - oder Programmierjargon als solche - verwenden wir das Wort Eimer für das, was ich Gefäß genannt habe. Manchmal muss man auf andere Wörter zurückgreifen, um die Bedeutung der gebräuchlichen Jargonwörter zu verstehen.

Wenn Sie Vererbung verstehen, was wahrscheinlich jeder Leser hier tun wird, dann ist die einzige Sache, auf die Sie achten müssen, dass das Gefäß, ich. e. Der für den Fang verwendete Bucket muss vom gleichen Typ oder weniger abgeleiteten Typ sein als der, der übergeben wird - dies gilt sowohl für die Kovarianz als auch für die Kontravarianz.

Die Vererbung sagt, dass Sie einen Vogel in einem Tiereimer fangen können, weil der Vogel ein Tier ist. Wenn also ein Parameter einer Methode einen Vogel fangen muss, könnte man ihn in einem Tiereimer fangen (ein Parameter vom Typ Tier), was dann eine Kontravarianz ist. Und wenn Ihre Methode, dh Ihr Delegat einen Vogel zurückgibt, dann kann der "Eimer" auch vom Typ Vogel oder weniger abgeleiteten (eines Elterntyps) sein, was bedeutet, dass die Variable, von der Sie den Rückgabewert der Methode erhalten, der sein muss gleicher oder weniger abgeleiteter Typ als der Rückgabewert.

Wechseln Sie einfach Ihr Denken, um zu unterscheiden zwischen dem, was passiert wird und dem, was fängt, denn dann löst sich die ganze Komplexität von Kovarianz und Kontravarianz auf. Dann erkennen Sie, dass das gleiche Prinzip am Werk ist. Es ist nur so, dass die Vererbung nicht verletzt werden kann, da sie nur in einer Richtung fließt.

Und der Compiler ist so schlau, dass, wenn Sie den Bucket in den spezialisierteren Typ (wieder, und wie nötig) umwandeln, dann und nur dann erhalten Sie alle spezialisierten Methoden zurück, die in die abgeleitete Klasse hinzugefügt wurden. Das ist die Schönheit davon. Also, es ist fangen, werfen und benutzen, was Sie haben und vielleicht brauchen.

    
Andi 03.07.2015 12:52
quelle

Tags und Links