Home > Back-end >  Downcasting/Upcasting interface with generics to same interface but with different generics - C#
Downcasting/Upcasting interface with generics to same interface but with different generics - C#

Time:11-20

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.

CodePudding user response:

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{}
  • Related