2010-06-09 3 views
7

Kann jemand herausfinden, warum Contravarianz nicht mit C# -Werttypen funktioniert?Contravariant Delegates Werttypen

Die unten funktioniert nicht

private delegate Asset AssetDelegate(int m); 

internal string DoMe() 
{ 
    AssetDelegate aw = new AssetDelegate(DelegateMethod); 
    aw(32); 
    return "Class1"; 
} 

private static House DelegateMethod(object m) 
{ 
    return null; 
} 
+1

Ich würde eine Antwort posten, aber ich möchte nicht mit dem Wortlaut fummeln. Überprüfen Sie den Blogeintrag von Eric Lippert hier, insbesondere die Kommentare. http://blogs.msdn.com/b/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx Es scheint zu sein a Bei Referenztyp "Werte" mit demselben Speicherbedarf, was bei Werttypen nicht der Fall ist. Mit dem gesagt, die DelgateMethod könnte generisch gemacht werden, die dann ints, longs usw. unterstützen würde. –

Antwort

5

Das Problem ist, dass ein Int kein Objekt ist.

Ein Int kann Box zu einem Objekt sein. Das resultierende Objekt (aka boxed int) ist natürlich ein Objekt, aber es ist nicht mehr genau ein int.

Beachten Sie, dass die "ist" Ich verwende oben ist nicht das gleiche wie der C# -Operator is. Mein "ist" bedeutet "ist umwandelbar durch implizite Referenzkonvertierung". Dies ist die Bedeutung von "ist", wenn wir über Kovarianz und Kontravarianz sprechen.

Ein int ist implizit in ein Objekt konvertierbar, aber dies ist keine Referenzkonvertierung. Es muss verpackt werden.

Ein House ist implizit in eine Asset über eine Referenzumwandlung konvertierbar. Sie müssen keine Objekte erstellen oder ändern.

Betrachten Sie das Beispiel unten. Beide Variablen house und asset verweisen auf das gleiche Objekt. Die Variablen integer und boxedInt haben dagegen den gleichen Wert, beziehen sich aber auf verschiedene Dinge.

House house = new House(); 
Asset asset = house; 

int integer = 42; 
object boxedInt = integer; 

Boxing and Unboxing ist nicht so einfach wie es aussehen könnte. Es hat viele Feinheiten und kann Ihren Code auf unerwartete Weise beeinflussen. Mischen von Boxen mit Kovarianz und Kontravarianz ist eine einfache Möglichkeit, jemanden zu blenden.

+0

In meinen Augen ist es nicht hilfreich zu versuchen, so zu tun, als wären Werttypen von 'System.Object' abgeleitet. Es ist viel hilfreicher zu erkennen, dass für jeden Werttyp ein zugehöriger "eingerahmter" Klassentyp existiert, der von "System.ValueType" abgeleitet ist. Werttypen sind implizit in ihre klassenähnlichen Entsprechungen konvertierbar, und eine explizite Umwandlung kann verwendet werden, um den Inhalt eines umkleideten Werttyps zurück in einen echten zu kopieren. – supercat

1

ich mit Anthony Pegram Kommentar zustimmen - es basiert auf Referenztypen einen anderen Speicherbedarf aufweisen als die Werttypen: die CLR kann implizit eine Klasse von einer Art verwenden, wie Eine Klasse des Super-Typs, aber wenn Sie mit der Verwendung von Werttypen beginnen, muss die CLR Ihre Ganzzahl so unterteilen, dass sie an der Stelle des Objekts funktionieren kann.

Wenn Sie schauen, um es trotzdem funktioniert, habe ich eine Tendenz, die Erklärung in einem Ausdruck zu wickeln:

AssetDelegate aw = new AssetDelegate((m) => DelegateMethod(m)); 

Ich weiß nicht, ob das eine gute Praxis ist oder nicht so weit wie Syntax geht , aber denken Sie daran, dass Boxen und Unboxing teuer ist.

Verwandte Themen