2009-04-12 3 views
1

Das folgende Beispiel stammt aus C# in Depth: What you need to master C# 2 and 3 und scheint nur eine brechende Änderung zu verursachen, wie jskeet festgestellt hat, aber falsch sein. Bitte erläutern:Contravarianz scheint ein konfliktbehaftetes Verhalten zu verursachen

delegate void SampleDelegate(string x); 

public void CandidateAction (string x) 
{ 
    Console.WriteLine("Snippet.CandidateAction") 
} 

public class Derived: Snippet 
{ 
    public void CandidateAction (object x) 
    { 
    Console.WriteLine("Derived.CandidateAction") 
    } 
} 
.... 

Derived x = new Derived(); 
SampleDelegate factory = new SampleDelegate (x.CandidateAction); 
factory ("test"); 

Nun, warum sollte es überhaupt als SampleDelegate Zeichenfolge akzeptieren arbeiten nicht das Objekt. Und meines Wissens ist Objekt nicht von der Zeichenkette abgeleitet. Es ist umgekehrt. Das erlaubt Contravarianz unter C# 2.0. Das scheint den gegenteiligen Effekt zu demonstrieren.

Dank

Antwort

3

Konzeptionell ist Derived.CandidateAction Unterschrift: „Ich jedes Objekt behandeln können Sie mich werfen wollen.“ Der Vertrag von SampleDelegate lautet "Sie müssen in der Lage sein, eine Zeichenfolge zu verarbeiten." Wenn nun eine Methode mit einem beliebigen Objekt umgehen kann, kann sie mit einer Zeichenfolge umgehen. Daher kann Derived.CandidateAction das, was SampleDelegate benötigt, erfüllen und kann daher einer SampleDelegate-Variablen zugewiesen werden.

Ich schrieb eine ausführlichere Diskussion dieser (freilich aus einer C# 4 Sicht) bei http://hestia.typepad.com/flatlander/2008/12/c-covariance-and-contravariance-by-example.html.

1

Kontravarianz ermöglicht Ihnen die Verwendung einer Methode mit Parametern, die ein Basistyp der Parameter in der Signatur der Delegiertenmethode sind.

Die Delegiertensignatur definiert, welche Typen an die Methode übergeben werden. Die Methode selbst kann Typen haben, die weniger "spezifisch" sind. In Ihrem Beispiel, wenn der Delegat aufgerufen wird, während die Zeichenfolge übergeben wird. Es ist vollkommen in Ordnung für die tatsächliche Methode, nur ein Objekt zu wollen, weil eine Variable vom Typ object eine Instanz vom Typ string enthalten darf.

Dies ist besonders nützlich in Ereignisszenarien Umgang mit dem Sie ein Event-Handler so schreiben können, die auf fast jedem Ereignis zugeordnet werden können (selbst wenn die args Parameter präziser wie ItemCheckedEventArgs geführt werden):

public void GenericHandler(object source, EventArgs args) { 
    //do something generic 
} 
Verwandte Themen