Warum funktioniert das nicht? Kann ich Delegatkovarianz nicht richtig verstehen?
%Vor%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?
Sie müssen ein generisches verwenden.
%Vor%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.
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.
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.
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).
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.
Tags und Links c# covariance delegates