首页 > 解决方案 > 使用约束作为类型传递泛型类型

问题描述

如果我有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.

标签: c#generics

解决方案


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

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

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

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

因为这条线是合法的:

cage.Add(new Tiger());

Cage<Animal>有一个方法Add需要Animal. ATiger是一个Animal所以必须是合法的。但这意味着我们只是把老虎关进了沙鼠笼。

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

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

  • 泛型类型是接口或委托
  • 可变类型参数是引用类型
  • 接口或委托已被标记为安全变化。

例如:

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

那是合法的。List<Tiger>implements IEnumerable<Tiger>,它是一个接口并标记为对协变安全,因此可以将其分配给IEnumerable<Animal>.

您会注意到,无法将鸭子放入动物序列中,因此无法将鸭子放入老虎序列中。这就是我们知道协方差是安全的


推荐阅读