将带约束的泛型类型作为类型<constraint>传递

时间:2018-05-09 22:01:56

标签: c# generics

如果我的GenericClass类型约束为where T : BaseType,为什么我不能将其作为GenericClass<BaseType>传递?

class GenericClass<T> where T : BaseType
{
    void Method()
    {
        new UtilityClass().Method(this);
    }
}

class UtilityClass
{
    internal void Method(GenericClass<BaseType> genericClass)
    {
    }
}

静态分析器错误:

Cannot convert from 'GenericsPoc.GenericClass<T>' to 
'GenericsPoc.GenericClass<GenericsPoc.BaseType>'

由于UtilityClass<T> T必须从BaseClass继承,我没想到这一点。

2 个答案:

答案 0 :(得分:4)

每天都会问这个问题。再一次!

class Cage<T> where T : Animal
{
  public void Add(T t) { ... }
}

现在你的问题是:为什么这是非法的?

Cage<Animal> cage = new Cage<Gerbil>();

因为这条线是合法的:

cage.Add(new Tiger());

Cage<Animal>Add方法AnimalTigerAnimal,因此必须合法。但这意味着我们只是将一只老虎放入沙鼠笼中。

由于该行必须合法且导致类型错误,因此某些其他行必须是非法的,现在您知道它是哪一行。

您想要的功能称为通用协方差 在C#中是合法的:

  • 泛型类型是接口或委托
  • 变化类型参数是引用类型
  • 已将接口或代理标记为方差安全。

例如:

IEnumerable<Animal> animals = new List<Tiger>() { new Tiger() };

这是合法的。 List<Tiger>实现IEnumerable<Tiger>,这是一个接口并标记为协方差安全,因此可以将其分配给IEnumerable<Animal>

你会注意到没有办法将鸭子放入一系列动物,因此没有办法将鸭子放入一系列老虎中。 这就是我们如何知道它对协方差是安全的

答案 1 :(得分:2)

您需要修改UtilityClass,以便该方法也传递通用类型:

internal void Method<T>(GenericClass<T> genericClass) where T: BaseType
{
}