为什么要使用带有接口约束的泛型?

Why to use generic with interface constraint?

在创建通用接口时,我可以定义通用参数应从特定接口 (IBase) 继承的约束。

interface IGeneric<T> where T : IBase
{
    List<T> property{get; set;}
}

这个有什么用吗?因为我可以将其替换为以下界面,它具有相同的目的并且更简单。

interface IGeneric
{
    List<IBase> property{get; set;}
}

在我看来,在这种情况下我们根本不需要泛型,因为我们已经知道 T 将是 IBase。 IBase 属性 已经可以容纳所有派生类型。那么具有特定接口约束的泛型有什么用呢?

这两个接口是很不一样的,因为List<T>List<IBase>是很不一样的。假设有一个 class A 实现了 IBase。首先,这不编译:

IGeneric noTypeParameter = ...
noTypeParameter.property = new List<A>();

但是这样做:

IGeneric<A> hasTypeParameter = ...
noTypeParameter.property = new List<A>();

这是因为 ListT 上不是协变的。事实上它是不变的。另见:Convert List<DerivedClass> to List<BaseClass>

如果你使用 IEnumerable<T>IEnumerable<IBase> ,那么上面的两个代码片段都可以编译,但是两个 IGeneric 接口仍然不同,因为:

IGeneric noTypeParameter = ...
IEnumerable<A> enumerable = noTypeParameter.property; // does not compile


IGeneric<A> hasTypeParameter = ...
IEnumerable<A> enumerable = noTypeParameter.property; //does compile

所以基本上,使用通用参数,您可以将特定类型的 List 传递给接口,并获取特定类型的 List 。但是,您不能“存储任何 IBase 实现的 property”。如果没有类型参数,您可以存储任何 IBase 实现的 property,但您无法获取特定类型 of/into IGeneric.