当处理协变接口时,我有一个完整的wtf时刻。带接口的泛型协方差 - “is”和“=”运算符之间的奇怪行为矛盾
考虑以下几点:
class Fruit { }
class Apple : Fruit { }
interface IBasket<out T> { }
class FruitBasket : IBasket<Fruit> { }
class AppleBasket : IBasket<Apple> { }
注:
AppleBasket
不从继承。IBasket
是covariant。
后来在脚本,你写的:
FruitBasket fruitBasket = new FruitBasket();
AppleBasket appleBasket = new AppleBasket();
Log(fruitBasket is IBasket<Fruit>);
Log(appleBasket is IBasket<Apple>);
...和你所期望的输出是:
true
true
不过,请考虑以下代码:
AppleBasket appleBasket = new AppleBasket();
Log(appleBasket is IBasket<Fruit>);
你会期望它输出true
,对吧?那么,你是错误 - 至少我反正编译:
false
这是奇怪的,但也许它的执行隐式转换,类似转换的int
到long
。 int
不是long
的一种,但long可以隐式地赋予int的值。
无论其,考虑下面的代码:
IBasket<Fruit> basket = new AppleBasket(); // implicit conversion?
Log(basket is IBasket<Fruit>);
此代码运行得很好 - 没有编译器错误或异常 - 尽管我们之前了解到的AppleBasket
是不是一种IBasket<Fruit>
。除非有第三种选择,否则它必须在分配中进行隐式转换。
当然basket
- 声明为IBasket<Fruit>
- MUST是IBasket<Fruit>
一个实例......我的意思是,这就是它被宣布为。对?
但是不行,根据is
运营商,你又错了!它输出:
false
...含义IBasket<Fruit> fruit
不是IBasket<Fruit>
实例......咦?
...含义以下属性:
IBasket<Fruit> FruitBasket { get { ... } }
有时可以返回一些两个不为空,并不是IBasket<Fruit>
一个实例。
进一步,ReSharper的告诉我,appleBasket is IBasket<Fruit>
是多余的在appleBasket
是提供类型的总是,并能与appleBasket != null
安全地更换... ReSharper的听错了吗?
那么,这是怎么回事?这只是我的C#版本(Unity 5.3.1p4 - 它是Unity的Mono自己的分支,基于.NET 2.0)是一个坚果吗?
呃,你运行的是什么版本的.NET? 'appleBasket is IBasket'为我打印'true'。看[小提琴](https://dotnetfiddle.net/aiNzDA)复制。 –
Rob
对我来说它工作,即使我有兴趣看看哪个版本的.Net。 –
在Unity 5.3.1p4中提供的Mono版本 - 它是Unity基于.NET 2.0的Mono自己的分支 – Hatchling