Ich hatte beim Umgang mit kovarianten Interfaces einen kompletten WTF-Moment.Generische Kovarianz mit Interfaces - Seltsamer Verhaltenswiderstand zwischen "is" - und "=" -Operatoren
Beachten Sie Folgendes:
class Fruit { }
class Apple : Fruit { }
interface IBasket<out T> { }
class FruitBasket : IBasket<Fruit> { }
class AppleBasket : IBasket<Apple> { }
Hinweis:
AppleBasket
erbt nicht vonFruitBasket
.IBasket
ist kovariant.
Später im Skript, schreiben Sie:
FruitBasket fruitBasket = new FruitBasket();
AppleBasket appleBasket = new AppleBasket();
Log(fruitBasket is IBasket<Fruit>);
Log(appleBasket is IBasket<Apple>);
... und wie man erwarten würde, ist der Ausgang:
true
true
Beachten Sie jedoch,, den folgenden Code:
AppleBasket appleBasket = new AppleBasket();
Log(appleBasket is IBasket<Fruit>);
Sie würden erwarten, dass es ausgegeben wird true
, richtig? Nun, Sie sind falsch - zumindest mit meinem Compiler trotzdem:
false
Das ist seltsam, aber vielleicht ist es die Durchführung einer implizite Konvertierung, ähnlich wie eine int
zu einem long
konvertieren. Eine int
ist keine Art von long
, aber eine lange kann den Wert eines int implizit zugewiesen werden.
JEDOCH betrachten diesen Code:
IBasket<Fruit> basket = new AppleBasket(); // implicit conversion?
Log(basket is IBasket<Fruit>);
Dieser Code läuft ganz gut - keine Compiler-Fehler oder Ausnahmen - auch wenn wir gelernt vorher, dass ein AppleBasket
nicht eine Art von IBasket<Fruit>
ist. Sofern es keine dritte Option gibt, muss eine implizite Konvertierung in der Zuweisung vorgenommen werden.
Sicher basket
- erklärt als IBasket<Fruit>
- MUST eine Instanz IBasket<Fruit>
sein ... ich meine, das ist, was es war, als erklärt. Recht?
Aber nein, nach dem is
Operator, Sie sind wieder falsch! Es gibt:
false
... Bedeutung IBasket<Fruit> fruit
keine Instanz IBasket<Fruit>
ist ... Huh?
...Gemeint ist die folgende Eigenschaft:
IBasket<Fruit> FruitBasket { get { ... } }
manchmal etwas zurückgeben, die beide nicht null ist, und ist keine Instanz von IBasket<Fruit>
.
WEITERE, sagt ReSharper mir, dass appleBasket is IBasket<Fruit>
redundant ist, dass appleBasket
ist immer der dargebotenen Art, und kann sicher mit appleBasket != null
ersetzt werden ... ReSharper bekam auch etwas falsch gemacht?
Also, was ist hier los? Ist das nur meine Version von C# (Unity 5.3.1p4 - It's Unity's eigener Zweig von Mono, basierend auf .NET 2.0), der eine Nuss ist?
Uh, welche Version von .NET laufen Sie? 'appleBasket is IBasket' druckt 'true' für mich. Siehe [die Geige] (https://dotnetfiddle.net/aiNzDA), um zu replizieren. –
Rob
für mich funktioniert es, auch ich bin interessiert zu sehen, welche Version von '.Net'. –
Die Version von Mono, die in Unity 5.3.1p4 zur Verfügung gestellt wird - Es ist Unity's eigener Zweig von Mono, basierend auf .NET 2.0 – Hatchling