Sie können nicht Kovarianz für Werttypen verwenden:Wie wird die Kovarianz für Werttypen verwendet?
Func<string> refTypeFunc =() => "foo";
Func<int> valueTypeFunc =() => 123;
Func<object> a = refTypeFunc; // works
Func<object> b = valueTypeFunc; // doesn't work
This answer by Jon Skeet erklärt, warum:
Grundsätzlich Varianz gilt, wenn die CLR sicherstellen kann, dass es keine gegenständlich Veränderung zu machen braucht zu den Werten. Alle Referenzen sehen gleich aus - Sie können also
IEnumerable<string>
alsIEnumerable<object>
ohne Änderung der Darstellung verwenden; Der native Code selbst muss nicht wissen, was Sie mit den Werten überhaupt machen, solange die Infrastruktur garantiert hat, dass sie definitiv gültig ist.Bei Werttypen funktioniert das nicht - um einen
IEnumerable<int>
alsIEnumerable<object>
zu behandeln, müsste der Code, der die Sequenz verwendet, wissen, ob eine Box-Konvertierung durchgeführt werden soll oder nicht.
Nun, kacken. Zumindest für Func
können Sie dies tun:
Func<object> c =() => valueTypeFunc();
jedoch so eine einfache Art und Weise können Sie das nicht für die meisten Fälle verwendet werden. Sagen, ich habe eine Schnittstelle wie folgt definiert:
interface ICovariant<out T>
{
Func<T> InnerFunc { get; }
}
Nun, wenn ich eine ICovariant<T>
haben, ich es nicht ICovariant<object>
werfen kann, und ich sehe keinen einfachen Weg aus ihm heraus. Ich weiß T
kann ein object
sein - alles kann. Was kann ich in diesem Fall tun? Wenn es keine einfache Problemumgehung gibt, was wäre sonst der beste Ansatz?
Vielleicht fragen Sie sich, warum Ihr Entwurf Sie braucht generische Werte 'object' zu werfen, die im Grunde ist das Besiegen der gesamte Zweck von Generika an erster Stelle. – juharr
@juharr Sowohl die Implementierung als auch die Verwendung ist bei Verwendung von Generika viel sauberer. Es gibt eine Methode, die 'T' zurückgibt - das Zurückgeben von' object' würde eine Menge hässlichen Downcasting im Aufrufcode hinzufügen. Und "T" als ein "Objekt" zu verwenden wäre sehr nützlich für Polymorphie, sagen wir viele meiner Objektinstanzen zu einer Liste hinzufügen. –
Wenn Sie sicherstellen möchten, dass es keine gegenständlichen Änderungen gibt, kleben Sie einfach eine 'where T: Klasse' dort hinein. –