Varianz wird nur auf sichere Weise unterstützt - tatsächlich unter Verwendung der Fähigkeiten, über die die CLR bereits verfügt. Die Beispiele, die ich in dem Buch gebe, in dem versucht wird, a List<Banana>
als List<Fruit>
(oder was auch immer es war) zu verwenden, funktionieren also immer noch nicht - aber einige andere Szenarien werden es tun.
Erstens wird es nur für Schnittstellen und Delegaten unterstützt.
Zweitens muss der Autor der Schnittstelle / des Delegaten die Typparameter als in
(für Kontravarianz) oder out
(für Kovarianz) dekorieren . Das offensichtlichste Beispiel ist, IEnumerable<T>
dass Sie nur Werte "herausnehmen" können - Sie können keine neuen hinzufügen. Das wird werden IEnumerable<out T>
. Das schadet der Typensicherheit überhaupt nicht, aber Sie können beispielsweise IEnumerable<string>
eine Methode zurückgeben, die als zurückgegeben deklariert wurde IEnumerable<object>
.
Kontravarianz ist schwieriger, konkrete Beispiele für die Verwendung von Schnittstellen zu nennen, aber mit einem Delegierten ist es einfach. Bedenken Sie, Action<T>
dass dies nur eine Methode darstellt, die einen T
Parameter akzeptiert. Es wäre schön, wenn Sie a Action<object>
as nahtlos konvertieren Action<string>
könnten - jede Methode, die einen object
Parameter verwendet, ist in Ordnung, wenn sie mit a dargestellt wirdstring
, statt. Natürlich weist C # 2 bereits eine gewisse Kovarianz und Kontravarianz von Delegaten auf, jedoch über eine tatsächliche Konvertierung von einem Delegatentyp in einen anderen (Erstellen einer neuen Instanz) - Beispiele finden Sie auf P141-144. C # 4 wird dies allgemeiner machen und (glaube ich) vermeiden, eine neue Instanz für die Konvertierung zu erstellen. (Es wird stattdessen eine Referenzkonvertierung sein.)
Hoffe das klärt es ein bisschen auf - bitte lass es mich wissen, wenn es keinen Sinn ergibt!