关于泛型和继承(原谅我的坏标题)

本文关键字:原谅我 我的 标题 原谅 于泛型 泛型 继承 | 更新日期: 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
}