Arrcival
Arrcival

Reputation: 169

How to use a list of items (heriting from an abstract class) as its abstract class?

Here's a short example of the issue I'm encountering

I have two abstract classes EntityAbs and ListEntityAbs :

public abstract class EntityAbs {
    //Save itself in a Database
    public abstract int SaveEntity();
}
public abstract class ListEntitiesAbs<T> where T : EntityAbs {
    protected List<T> InnerList;

    //Save each values in a Database
    public virtual int SaveEntities()
    {
        return InnerList.Sum(entity => entity.SaveEntity());
    }
}

Multiple classes that herits on EntityAbs and get it's own ListEntities (an example with a class named Item) :

public class Item : EntityAbs {
    public override int SaveEntity()
    {
        // Implements here how I save it
    }
}
public class Items : ListEntitiesAbs<Item>, IList<Item> { 
    // Has specific class stuff in it
}

Now, I would like to save every ListEntitiesAbs somewhere else on my database

public int Save(params ListEntitiesAbs<EntityAbs>[] lists)
{
    for(int i = 0; i < lists.Length; i++)
        lists[i].SaveEntities();
}

Items items = new Items();
// add items 
int result = Save(items);

But then, items (or any other list I add here) displays an error by Visual Studio, and I don't here why. The error says that it Cannot convert from Items to ListEntitiesAbs<EntityAbs>, but Items herits from ListEntitiesAbs and Item from EntityAbs..

Am I missing something ? I've tried casting as ListEntityAbs or using Cast<> but nothing fits

Any help is appreciated, as I'm not even sure if this kind of behavior is actually possible

Upvotes: 1

Views: 374

Answers (1)

JonasH
JonasH

Reputation: 36541

Well ListEntitiesAbs<T> is not covariant. This means that ListEntitiesAbs<Item> is not, and cannot be trivially converted to, ListEntitiesAbs<EntityAbs>.

Option 1: make Save generic

public int Save<T>(params ListEntitiesAbs<T>[] lists) where T:EntityAbs 
{
    for(int i = 0; i < lists.Length; i++)
       lists[i].SaveEntities();
}

Option 2: non generic interface. You could also make a covariant interface, but that does not seem to be needed in this particular case.

public interface IListEntitiesAbs {
    public int SaveEntities();
}
public int Save(params IListEntitiesAbs[] lists){
    ...
}

Upvotes: 2

Related Questions