Search code examples
c#generic-collections

How can I add child object to the parent generic type in c#


In java I can do it with extends keyword in Generic Type but in C# I cannot figure out.

I have a 3 classes, one of them is the base class.

public class BaseEntity { 
    public string Id {get;set;} 
}

public class EntityA : BaseEntity {}

public class EntityB: BaseEntity {}

Then I have a mock class for dataset. With generic type, the minimum constraint is the BaseEntity

public class MockDataStore<T> : IDataStore<T> where T : BaseEntity
{
    List<T> items = new List<T>();

    public async Task<bool> AddAsync(T item)
    {           
    }

    public async Task<bool> UpdateAsync(T item)
    {           
    }

    public async Task<bool> DeleteAsync(T item)
    {           
    }
}

But when I want to add one of the child class to the items list, the compailer says this is not possible.

Cannot convert From EntityA to T

items.Add(new EntityA());

I want to use the generic type, because of Add, Update and Delete methods.

Yes if I use the List<BaseEntity> = new List<BaseEntity>() then I will not get the cannot convert message. But in this case the Add, Update and Delete methods will be wrong.

However I have added where T : BaseEntity this constraints and grr.

What I want to achive is that the T : BaseEntity typed items list filled up with the child items of the BaseEntity.

How can I do it?


Solution

  • I think you have two options here:

    1. Remove the unneeded generics.

    I don't think you need generics here at the class level. You can just have a list of the base class and work with that:

    public class MockDataStore
    {
        List<BaseEntity> items = new List<BaseEntity>();
    
        public async Task<bool> AddAsync(BaseEntity item)
        {           
        }
    
        public async Task<bool> UpdateAsync(BaseEntity item)
        {           
        }
    
        public async Task<bool> DeleteAsync(BaseEntity item)
        {           
        }
    }
    

    2. Use generics through a proper inheritance chain.

    This is probably not what you want, as you would end up with multiple classes, but I will leave it here just in case:

    public abstract class MockDataStoreBase<T> : IDataStore<T> where T : BaseEntity
    {
        protected List<T> items = new List<T>();
    
        public virtual async Task<bool> AddAsync(T item)
        {           
        }
    
        public async Task<bool> UpdateAsync(T item)
        {           
        }
    
        public async Task<bool> DeleteAsync(T item)
        {           
        }
    }
    
    public class EntityADataStore : MockDataStoreBase<EntityA>
    {
        public override async Task<bool> AddAsync(EntityA item)
        {
            bool result = await base.AddAsync(item);
        }
    
        //...
    }
    

    Now, EntityADataStore.items will be a List<EntityA>.