Cur*_*tle 6 c# generics polymorphism interface
我一般都了解接口,继承和多态,但有一件事令我感到困惑.
在这个例子中,Cat实现了IAnimal,当然List实现了IList:
IList<IAnimal> cats = new List<Cat>();
Run Code Online (Sandbox Code Playgroud)
但它会生成编译错误(无法隐式转换类型...).如果我使用Cat继承的asbtract超类[Animal],它也将无效.但是,如果我用Cat替换IAnimal:
IList<Cat> cats = new List<Cat>();
Run Code Online (Sandbox Code Playgroud)
它编译得很好.
在我看来,因为Cat实现了IAnimal,所以第一个例子应该是可以接受的,允许我们返回列表和包含类型的接口.
谁能解释为什么它无效?我确信这是一个合乎逻辑的解释.
Eri*_*ert 20
有一个合乎逻辑的解释,这个问题几乎每天都在StackOverflow上提出.
假设这是合法的:
IList<IAnimal> cats = new List<Cat>();
Run Code Online (Sandbox Code Playgroud)
是什么阻止了这种合法?
cats.Add(new Giraffe());
Run Code Online (Sandbox Code Playgroud)
没有."猫"是动物的名单,长颈鹿是动物,因此你可以在猫的名单中添加长颈鹿.
显然,这不是类型安全的.
在C#4中,我们添加了一个功能,如果元数据注释允许编译器证明它是类型安全的,那么你可以这样做.在C#4中,您可以这样做:
IEnumerable<IAnimal> cats = new List<Cat>();
Run Code Online (Sandbox Code Playgroud)
因为IEnumerable<IAnimal>没有Add方法,所以没有办法违反类型安全.
有关详细信息,请参阅我在C#4中如何设计此功能的系列文章.
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx
(从底部开始.)
IList<T>出于类型安全原因,C#不支持这种差异.
如果C#支持这个,那么你期望在这里发生什么?
IList<IAnimal> cats = new List<Cat>();
cats.Add(new Dog()); // a dog is an IAnimal too
cats.Add(new Squirrel()); // and so is a squirrel
Run Code Online (Sandbox Code Playgroud)
在C#4中,您可以执行以下操作:
IEnumerable<IAnimal> cats = new List<Cat>();
Run Code Online (Sandbox Code Playgroud)
这是因为IEnumerable<T>界面确实支持这种方差.An IEnumerable<T>是一个只读序列,因此您无法随后将a Dog或a 添加Squirrel到IEnumerable<IAnimal>实际上是一个列表中Cat.