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 TParameter akzeptiert. Es wäre schön, wenn Sie a Action<object>as nahtlos konvertieren Action<string>könnten - jede Methode, die einen objectParameter 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!