Generics & Inheritance: What am I doing wrong here?

The following 4 properties have been announced:

abstract class AConfigAction {} abstract class APlugin<ConfigActionType> where ConfigActionType :AConfigAction {} class AppExecuteConfigAction : AConfigAction {} class AppExecutePlugin : APlugin<AppExecuteConfigAction>{} 
  • All classes are publicly available. The organs have been removed for simplicity.

Why can't it be converted?

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

cannot convert from 'AppExecutePlugin' to 'APlugin'


Full error message:

Error 1 The best overloaded method match for 'System.Collections.Generic.List> .Add (EnvironmentSwitcher.Model.ConfigAction.APlugin)' has some invalid arguments R: \ projects \ EnvironmentSwitcher \ EnvironmentSwitcher \ View \ ConfigurationActionManagerForm.cs 35

Error 2 Argument "1": cannot be converted from "EnvironmentSwitcher.Model.ConfigAction.AppExecute.AppExecutePlugin" to "EnvironmentSwitcher.Model.ConfigAction.APlugin" R: \ projects \ EnvironmentSwitcher \ EnvironmentSwitcher \ View \ ConfigurationActionManagerForm.

+4
source share
2 answers

Make it a little easier to understand:

 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? 

Suppose this was legal. What stops this?

 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 is of type Cage<Animal> , which means that it can contain any animal. But in fact, we know that this is a cage only for tigers. You just put the shark in a tiger cage, which seems uncomfortable for both the shark and the tiger.

Obviously this is not possible. What is in the way? The only thing that prevents it is that first of all, put the tiger cage in the collection of animals. A tiger cage is not some kind of animal cage, because there are things you can do with an animal cage that you cannot do with a tiger cage, namely, insert a shark into it. The basic principle of object-oriented design is that subtypes can do everything their supertypes can do; a tiger cage cannot do everything an animal cage can do, so it is not a subtype.

The higher the likelihood that generic types cannot be covariant in their type arguments, because it violates the Liskov Substitution Principle. In C # 4, some interfaces and delegates are covariant in their type arguments. For example, in C # 4 it is legal to put IEnumerable<Tiger> in List<IEnumerable<Animal>>> , because it cannot be dangerous. We can support the principle of substitution by allowing covariance, because IEnumerable<T> is the "external" interface. Do you only ever choose tigers; there is no way to place sharks.

+22
source

Covariance of generalizations and contravariance is supported in C # 4.0. It works with interfaces, although not with abstract classes:

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

In C # 3.5, this is not supported.

+4
source

Source: https://habr.com/ru/post/1388737/


All Articles