Search code examples
c#oopgenericsinterface

Downcasting/Upcasting interface with generics to same interface but with different generics - C#


I want to downcast interface IEntity<TM, TV, TP> to IEntity<IModel, IView, IPresenter>, but it gives me Invalid Cast Exception. I added some constraints (where), but it also didn't help.

Note: Im not entirely sure what is this will do, upcast or downcast in my situation

Better to show example in I try to use.


// Simple class, doesnt inherits anything.
// This class can't be generic
public class EntitiesContainer
{
    private List<IEntity<IModel, IView, IPresenter>> _entities = new ();

    // Adds IEntity<TM, TV, TC> to list of entities;
    public void Add<TM, TV, TC>(IEntity<TM, TV, TC> entity) 
        where TM : IModel 
        where TV : IView
        where TC : IPresenter
    {
        _entities.Add((IEntity<IModel, IView, IPresenter>)entity);  // invalid cast

        //or it says: argument type IEntity<TM, TV, TC> is not assignable to IEntity
        //_entities.Add(entity);  //syntax error
    }

    // some other methods below...
}

IEntity:

    public interface IEntity<TM, TV, TP> 
        where TM : IModel
        where TV : IView
        where TP : IPresenter
    {
        TM Model { get; }
        TV View { get; }
        TP Presenter { get; }
    }

This example I want to add IEntity to list. Class has a List of IEntity<IModel, IView, IPresenter>, but it is a problem to add IEntity with generic parameters. E.g. IEntity<ImplModel, ImplView, ImplPresenter, because it can't be downcasted/upcasted to <IEntity<IModel, IView, IPresenter>>

ImplModel, ImplView, ImplPresenter- they all Implements its interfaces respectively (IModel, IView, IPresenter)

I did some research. Looks like I need to use something called generics covariance. By documentation, I need to put in or out in class. But I have List of specific generics and in or out will not help.


Any help will be helpfull. Thanks.


Solution

  • You can add out specifier into your IEntity interface declaration and then remove cast completely

    class TestModel:IModel{}
    class TestView:IView{}
    class TestPresenter:IPresenter{}
    
    class TestEntity : IEntity<TestModel, TestView, TestPresenter>{}
    
    // Simple class, doesnt inherits anything.
    // This class can't be generic
    public class EntitiesContainer
    {
        private List<IEntity<IModel, IView, IPresenter>> _entities = new ();
    
        public void Test() => Add(new TestEntity());
        
        // Adds IEntity<TM, TV, TC> to list of entities;
        public void Add(IEntity<IModel, IView, IPresenter> entity) 
        {
            _entities.Add(entity);  // not cast at all
        }
    
        // some other methods below...
    }
    
    //------->>>Main changes here - *out* TModel, etc!!!
    public interface IEntity<out TModel, out TView, out TPresenter>
        where TModel : IModel
        where TView: IView
        where TPresenter : IPresenter    
    {
    }
    
    public interface IPresenter{}
    
    public interface IView{}
    
    public interface IModel{}