Using a base class as common to IEnumerable <T>

I have a good understanding of OOP in general, inheritance and polymorphism, interfaces, etc. I came across a strange situation, and I do not understand why it does not work at all ...

EDIT: Well, I found out that covariance (or contravariance?) Can solve this problem, but, to a decisive extent,

we are still using .NET 2.0

How can I solve this problem without switching to C # 4.0?

Here is the situation. Given these two classes:

public class CustomCollectionType<T> : IEnumerable<T> { /* Implementation here, not really important */ } public class Entity : EntityBase { /* Implentation here, not important */ } 

The compiler complains when I try to use this general method

 public void LoopThrough(IEnumerable<EntityBase> entityList) { foreach(EntityBase entity in entityList) { DoSomething(entity); } } 

And try using it like this:

 CustomCollectionType<Entity> entityList; /* Add items to list */ LoopThrough(entityList); 

The error says that I cannot convert from CustomCollectionType<Entity> to IEnumerable<EntityBase> .

However, I can do this:

 public void Foo(EntityBase entity) { entity.DoSomething(); } Foo(new Entity()); 

And this:

 public void Bar(IEnumerable<Entity> entityList) { ... } CustomCollectionType<Entity> entityList; Bar(entityList); 

Why can't I create my method with the highest classes in the hierarchy? The types are clearly compatible ... Am I missing something?

EDIT: I want to solve this problem without any changes to existing classes, so creating a new method in any of the classes or implementing an additional interface is out of the question.

+4
source share
4 answers

Consider your first case. You have:

 class Bowl<T> : IEnumerable<T> {} class Apple : Fruit {} ... void LoopThrough(IEnumerable<Fruit> fruits) ... 

and you call

 Bowl<Apple> apples = whatever; LoopThrough(apples); 

This does not work in C # 3.0; it succeeds in C # 4.0 because IEnumerable<T> now covariant in T; a sequence of apples can be used as a sequence of fruits.

To make it work in C # 3.0, you can use the Cast sequence operator.

 Bowl<Apple> apples = whatever; LoopThrough(apples.Cast<Fruit>()); 

To make it work in C # 2.0, execute the Cast sequence statement yourself. These are just a couple of lines of code.

Note that in C # 4.0 it still won’t legitimately say:

 Bowl<Fruit> fruits = new Bowl<Apples>(); 

because you can say:

 fruits.Add(new Orange()); 

and you just put an orange in a bowl that can only contain apples.

+15
source

Yes, .NET can be quite annoying, as it cannot use all of your common options in one shot. Instead, perhaps try a general approach like this to alleviate the problem.

 public void LoopThrough<T>(IEnumerable<T> entityList) where T : EntityBase { foreach(T entity in entityList) { DoSomething(entity as EntityBase); } } 
+4
source

Types are compatible, but incompatible, the main reason here is that you use the base type in the parameter as IEnumerable, and not the actual type, although the Entity base is an entity, because the rules for parameters and type restrictions have several consequences for the behavior of the general class. especially regarding inheritance and accessibility of participants.

General classes are invariant. In other words, if the input parameter indicates List<BaseClass>, you will get a compile-time error if you try to provide a List<DerivedClass> .

And that’s why you get this error, where, as in your last one, for example, T is the same.

However, it would be nice to work with interfaces, since all interfaces are compatible

  public class Entity : IEntityBase { /* Implentation here, not important */ } public void LoopThrough(IEnumerable<IEntityBase> entityList) { foreach(IEntityBase entity in entityList) { DoSomething(entity); } } 

and your method will work fine

 CustomCollectionType<Entity> entityList; LoopThrough(entityList); 

because entitylist is of type IEntityBase

Another thing you can try is typeof (get type) or use a throw and it should work

0
source

Maybe I missed something, but if your intent CustomCollectionType should be from the Entity base, but allowed to use IEnumerable, do not you have an IT base as the basis of the Entity base? such as...

 public class CustomCollectionType<T> : EntityBase, IEnumerable<T> { /* Implementation here, not really important */ } 

Then your LoopThrough SHOULD work, since the custom collection type is derived from EntityBase and has all the expected methods, properties, etc. available ... or the worst case, you must enter it when calling a function such as

 Bowl<Apple> apples = whatever; LoopThrough((EntityBase)apples); 
0
source

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


All Articles