泛型与继承:我在这里做错了什么?

Ody*_*dys 4 c# polymorphism inheritance casting .net-3.5

声明了以下4个对象:

abstract class AConfigAction {}

abstract class APlugin<ConfigActionType> where ConfigActionType :AConfigAction {}

class AppExecuteConfigAction : AConfigAction {}

class AppExecutePlugin : APlugin<AppExecuteConfigAction>{}
Run Code Online (Sandbox Code Playgroud)
  • 所有课程都是公开的.为简单起见,已移除了实体.

为什么这不能转换?

_plugins = new List<APlugin<AConfigAction>>();
_plugins.Add(new AppExecutePlugin());  <--- Error
Run Code Online (Sandbox Code Playgroud)

无法从'AppExecutePlugin'转换为'APlugin'


完整的错误消息:

错误1'System.Collections.Generic.List> .Add(EnvironmentSwitcher.Model.ConfigAction.APlugin)'的最佳重载方法匹配有一些无效参数R:\ projects\EnvironmentSwitcher\EnvironmentSwitcher\View\ConfigurationActionManagerForm.cs 35

错误2参数'1':无法从'EnvironmentSwitcher.Model.ConfigAction.AppExecute.AppExecutePlugin'转换为'EnvironmentSwitcher.Model.ConfigAction.APlugin'R:\ projects\EnvironmentSwitcher\EnvironmentSwitcher\View\ConfigurationActionManagerForm.cs 35

Eri*_*ert 22

让我们更容易理解:

abstract class Animal {} // was AConfigAction
abstract class Cage<T> where T : Animal {} // was APlugIn
class Tiger : Animal {} // was AppExecuteConfigAction
class TigerCage : Cage<Tiger>{} // was AppExecutePlugin

var cages = new List<Cage<Animal>>();    
cages.Add(new TigerCage()); // Why is this an error?
Run Code Online (Sandbox Code Playgroud)

假设这是合法的.什么阻止了这个?

class Shark : Animal {} // some other config action
...
var cages = new List<Cage<Animal>>();    
cages.Add(new TigerCage()); 
Cage<Animal> firstCage = cages[0]; 
firstCage.InsertIntoCage(new Shark());
Run Code Online (Sandbox Code Playgroud)

firstCage的类型Cage<Animal>意味着它可以容纳任何种类的动物.但实际上我们知道这只是一只只有老虎的笼子.你只是将鲨鱼放入虎笼中,这对鲨鱼和老虎来说都是不舒服的.

显然不能允许.是什么阻止了它?唯一能阻止它的是,首先将虎笼放入动物笼子的集合中是违法的.虎笼不是一种动物笼子,因为你可以用动物笼子做一些你不能用虎笼做的事情,就是把鲨鱼放进去.面向对象设计的基本原则是子类型可以完成超类型可以做的所有事情; 老虎笼不能做动物笼子可以做的所有事情,所以它不是一个亚型.

更高调的方式是说,泛型类型不能在其类型参数中变成协变,因为这样做会违反Liskov替换原则.在C#4中,某些接口和委托在其类型参数中协变的.例如,在C#4中放入IEnumerable<Tiger>a 是合法的,List<IEnumerable<Animal>>>因为不可能使它变得不安全.我们可以在允许协方差的同时坚持替代原则,因为它IEnumerable<T>是一个"只有"的界面.你只带老虎出去; 没有办法把鲨鱼放进去.