关于泛型和继承(原谅我的坏标题)
本文关键字:原谅我 我的 标题 原谅 于泛型 泛型 继承 | 更新日期: 2023-09-27 18:21:36
由于我不知道我的问题是如何命名的,我不能保证最近或根本没有人问过同样的问题。
然而,我确实注意到有相当多的线程具有类似的标题,但它们似乎与我的问题无关。
我有一个自定义列表类,它实现了泛型。
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 */ }
}
我也有课程:
class Apple : Fruit
和
class Banana : Fruit
现在,相关代码来了:
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?
尽管appleList是MyList(Of Apple),Apple是Fruit,但当询问MyList(For Fruit)时,VisualStudio不接受MyList(From Apple)作为论据。
然而,如果我这样声明列表:
MyList<object> fruitList = new MyList<object>();
然后一切又正常了。我到底做错了什么?
非常感谢您的回答,感谢您花时间阅读,即使没有回答。
您正在尝试使用协方差
.Net只支持接口上的通用差异,所以这不起作用。
此外,协方差只对不可变类型有意义
如果可以将MyList<Apple>
转换为MyList<Fruit>
,那么就可以向列表中添加Orange
,这违反了类型安全性。
相反,您可以使该方法通用:
public void Add<U>(IList<U> list) where U : T
我认为IMyList接口的设计应该是:
public interface IMyList<T> : IEnumerable<T>
{
void Add(T item);
void AddRange(IEnumerable<T> itemList);
}
一切如预期。为什么?因为在.NET 4.0中,IEnumerable接口的类型参数T是协变的,所以定义如下:
public interface IEnumerable<out T> : IEnumerable
IMyList接口(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
}