声明了以下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>
答案 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)
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中,这不受支持。