oRoiDev
oRoiDev

Reputation: 349

Cannot add a derived class object to a list of it's base class type

I have the following class structure:

//BaseClass
public abstract class BaseClass<T> where T : Model
{
    public abstract T Data { get; set; }
    public BaseClass(T data) { Data = data; }
}

public abstract class Model
{
    public int Id { get; set; }
}

//ClassA
public class BaseClassA : BaseClass<ModelA>
{
    public override ModelA Data { get; set; }
    public BaseClassA(ModelA data) : base(data) { }
}

public class ModelA : Model { }

//ClassB
public class BaseClassB : BaseClass<ModelB>
{
    public override ModelB Data { get; set; }
    public BaseClassB(ModelB data) : base(data) { }
}

public class ModelB : Model { }

I would like to use them as follows:

List<BaseClass<Model>> myBaseList = new List<BaseClass<Model>>();
myBaseList.Add(new BaseClassA(new ModelA()));
myBaseList.Add(new BaseClassB(new ModelB()));

foreach (var item in myBaseList)
{
    if (item.Data.Id > 0)
    {
        //do stuff
    }
}

But I get the compiler exception:

cannot convert from BaseClassA to BaseClass<Model>

However, I was under the impresion that BaseClassA being of type BaseClass<ModelA> would be meet the requirement of being of type BaseClass<Model>.

For instance, this doesn't generate any errors:

List<Model> myModelList = new List<Model>();
myModelList.Add(new ModelA());
myModelList.Add(new ModelB());

I can't seem to wrap my head around where I went wrong with this.

Upvotes: 1

Views: 860

Answers (1)

Johnathan Barclay
Johnathan Barclay

Reputation: 20353

One possible solution would be to introduce a covariant interface:

public interface IBase<out T> where T : Model
{
    T Data { get; }
}

public abstract class BaseClass<T> : IBase<T> where T : Model

Then use the interface for your list:

var myBaseList = new List<IBase<Model>>();
myBaseList.Add(new BaseClassA(new ModelA()));
myBaseList.Add(new BaseClassB(new ModelB()));

Because IBase declares Data as get-only, this ensures type-safety.

And here you still have access to Data:

foreach (var item in myBaseList)
{
    if (item.Data.Id > 0)
    {
        //do stuff
    }
}

Upvotes: 4

Related Questions