为什么要在接口约束下使用泛型?

问题描述

在创建通用接口时,我可以定义通用参数应从特定接口(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>非常不同。假设有一个实现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。但是,您不能“存储任何property实现的IBase”。如果没有类型参数,则可以存储任何property实现的IBase,但不能从IGeneric中获取特定类型。