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

时间:2011-12-31 16:11:28

标签: c# inheritance .net-3.5 casting polymorphism

声明了以下4个对象:

abstract class AConfigAction {}

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

class AppExecuteConfigAction : AConfigAction {}

class AppExecutePlugin : APlugin<AppExecuteConfigAction>{}
  • 所有课程都是公开的。为简单起见,已删除了尸体。

为什么无法转换?

_plugins = new List<APlugin<AConfigAction>>();
_plugins.Add(new AppExecutePlugin());  <--- Error
  

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


完整的错误消息:

  

错误1'System.Collections.Generic.List&gt; .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 < / p>

2 个答案:

答案 0 :(得分: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?

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

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());

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

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

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

答案 1 :(得分:4)

C#4.0支持

Generics covariance and contravariance。它适用于接口,而不是抽象类:

abstract class AConfigAction { }

interface APlugin<out ConfigActionType> where ConfigActionType : AConfigAction { }

class AppExecuteConfigAction : AConfigAction { }

class AppExecutePlugin : APlugin<AppExecuteConfigAction> { }

class Program
{
    public static void Main()
    {
        var _plugins = new List<APlugin<AConfigAction>>();
        _plugins.Add(new AppExecutePlugin());
    }
}

在C#3.5中,这不受支持。