繁体   English   中英

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

[英]Generics & Inheritance: What am I doing wrong here?

声明了以下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> .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

让我们更容易理解:

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<Tiger>是合法的,因为没有办法使它不安全。 我们可以在允许协方差的同时维护替换原则,因为IEnumerable<T>是一个“out-only”接口。 你只带老虎出去; 没有办法把鲨鱼放进去。

C#4.0支持泛型协方差和逆变 它适用于接口,而不是抽象类:

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中,这不受支持。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM