为什么这段代码能适用于不同的数据类型?

5

我正在处理一些课堂示例。这段代码可以工作,但我不知道为什么它能工作。我知道有一个通用类型,而且该类实现了Item接口,但Item只是另一个类。为什么这段代码会允许将int和double放入同一个列表中。

我确信这与泛型有关,但我并不确定。

问题:为什么这段代码允许两种不同类型进入同一个列表?

类定义:

public class Item<T> : Item
{
}

public class Item
{
}

代码:

static void Main(string[] args)
{
    var list = new List<Item>();

    list.Add(new Item<int>());
    list.Add(new Item<double>());
}

提示:T是一个类型参数。请考虑一下这两个词的含义。 - Robert Harvey
1
代码太多了。尽量保持问题代码简短明了。 - H H
Item<T>、Item<int>和Item<double>都是通过继承实现的Item。由于您将Item存储在集合中,因此它们都可以被存储。 - kenny
1
我已将您的代码剥离到相关部分。 - Ant P
4个回答

7

您的困惑来自于您有两个泛型类型,而不是一个。第一个是泛型列表,您已经理解了。第二个是泛型Item类:

public class Item<T> : Item

这个类的定义表明,无论T是什么类型,Item<T>始终继承自Item。这意味着,当你创建一个List<Item>时...

var list = new List<Item>();

你可以添加任何 Item<T> 到它里面,因为任何 Item<T> 都是一个 Item


4
为什么这段代码能够将int和double存储在同一个列表中?
因为你存储的是“Item”,而不是“Item ”。
下面是等价的代码,更容易理解:
//list.Add(new Item<int>());
Item item1 = new Item<int>();   // implicit conversion from Item<int> to Item
list.Add(item1);

//list.Add(new Item<double>());
Item item2 = new Item<double>();
list.Add(item2);

这里展示的方法更容易理解。有时候,当你开始添加继承时,会让事情变得更加混乱。我仍然觉得奇怪的是,你可以让一个类继承另一个类,然后实现子类,但在对象的实际情况中,它们都是同一基类类型的对象,因此它们可以被推入某种集合中。 - Doug Hauf

2
它之所以可行,是因为Item<T> 一个Item,因此List<Item>可以放置Item<double>Item<int>。造成困惑的部分可能源于您正在为不同的类使用类似的类型名称(ItemItem<T>)。虽然在您的情况下一个继承自另一个,但类与该类的通用版本之间没有内置连接。

1
您示例中令人困惑的是基类和派生类都带有“Item”标签。然而,通过更改一些名称,您的代码等效于:
public class Pet {}
public class Dog : Pet {}
public class Cat : Pet {}

static void Main(string[] args)
{
    var list = new List<Pet>(); //  base type items

    list.Add(new Dog());
    list.Add(new Cat());
}

尽管列表中存储了两种不同的类型,它们都是从相同的基类派生而来。理解代码的关键在于 List<> 是一个基于基本类型 "Pet" 的容器 - 在您的示例中,基本类型是 "Item"。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接