关于泛型和继承(请原谅我不好的标题)

发布于 2024-12-28 23:07:00 字数 1151 浏览 2 评论 0原文

由于我不知道我的问题是如何称呼的,我不能保证最近没有人问过同样的问题,或者根本没有人问过同样的问题。

然而,我确实注意到有很多线程具有相似的标题,但它们似乎与我的问题无关。

我有一个自定义列表类,它实现了泛型。

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(Of Fruit) 时,VisualStudio 不接受 MyList(Of Apple) 作为参数。

但是,如果我像这样声明列表:

MyList<object> fruitList = new MyList<object>();

那么一切都会恢复正常。我究竟做错了什么?

如果您能得到答案,我们将不胜感激,并且感谢您花时间阅读,即使没有回答。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

旧情勿念 2025-01-04 23:07:00

您正在尝试使用协方差
.Net 仅支持接口上的通用差异,因此这是行不通的。

此外,协方差仅对不可变类型有意义。
如果可以将 MyList 转换为 MyList,那么您就可以将 Orange 添加到列表,违反类型安全。

相反,您可以使该方法变得通用:

public void Add<U>(IList<U> list) where U : T

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
邮友 2025-01-04 23:07:00

我认为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 接口的简单实现(列表装饰器):

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
}

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文