Reputation: 6144
As I don't know how my problem is called, I cannot guarantee, that nobody has asked the same question recently or at all.
I did notice, however that there are quite a few threads with a similar title, but they don't seem to be relevant to my problem.
I have a custom list class, that implements Generics.
class MyList<T>
{
public void add(T item) // adds an item to the list
{ /* code */ }
public void add(MyList<T> list) // attaches an existing list to the end of the current one
{ /* code */ }
}
I also have the classes:
class Apple : Fruit
and
class Banana : Fruit
Now, comes the relevant code:
MyList<Fruit> fruitList = new MyList<Fruit>();
// fill fruitList
fruitList.add(new Apple()); // works, of course
fruitList.add(new Banana()); // works as well, of course
MyList<Apple> appleList = new MyList<Apple>();
// fill appleList
fruitList.add(appleList); // doesn't work. Why?
Even though appleList is a MyList(Of Apple) and Apple is Fruit, VisualStudio doesn't accept MyList(Of Apple) as argument, when MyList(Of Fruit) is asked.
However, if I were to declare the list like this:
MyList<object> fruitList = new MyList<object>();
Then everything works again. What exactly did I do wrong?
An answer would be much appreciated, and thank you for taking the time to read, even without answering.
Upvotes: 10
Views: 302
Reputation: 18136
I think the design of IMyList interface should be:
public interface IMyList<T> : IEnumerable<T>
{
void Add(T item);
void AddRange(IEnumerable<T> itemList);
}
Everything works as expected. Why? Just because in .NET 4.0 IEnumerable interface is covariant in it's type parameter T, this is what the definition looks like:
public interface IEnumerable<out T> : IEnumerable
Simple implementation of IMyList interface (List decorator):
public class MyList<T> : IMyList<T>
{
private readonly List<T> _list = new List<T>();
#region Implementation of IMyList<in T>
public void Add(T item)
{
Console.WriteLine("Adding an item: {0}", item);
_list.Add(item);
}
public void AddRange(IEnumerable<T> itemList)
{
Console.WriteLine("Adding items!");
_list.AddRange(itemList);
}
#endregion
#region Implementation of IEnumerable
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
Upvotes: 3
Reputation: 888283
You're trying to use covariance.
.Net only supports generic variance on interfaces, so that won't work.
In addition, covariance only makes sense on immutable types.
Had it been possible to convert a MyList<Apple>
to a MyList<Fruit>
, you would then be able to add an Orange
to the list, violating type safety.
Instead, you can make the method generic:
public void Add<U>(IList<U> list) where U : T
Upvotes: 8