类的泛型类型不能接受类的派生类型的泛型类型



可能重复:
铸造列表<gt;的派生类列表<gt;基本类

这个标题可能讲不通。查看代码:

class Person {}
class Manager : Person {}
class PaymentCalculator<T> where T : Person
{
    public double Calculate(T person)
    {
        return 0;    // calculate and return
    }
}
class Calculators : List<PaymentCalculator<Person>>
{
    public Calculators()
    {
        this.Add(new PaymentCalculator<Person>());
        this.Add(new PaymentCalculator<Manager>());     // this doesn't work
        PassCalculator(new PaymentCalculator<Person>());
        PassCalculator(new PaymentCalculator<Manager>());   // this doesn't work
    }
    public void PassCalculator(PaymentCalculator<Person> x)
    { }
}

代码中标记为"这不起作用"的两行代码无法编译。

我可以解决这个问题,但我的意图似乎没有错。或者,是吗?

即使ManagerPerson继承,PaymentCalculator<Manager>也不会从PaymentCalculator<Person>继承。如果PaymentCalculator<T>是反变量的,它会起作用,但类在中不能是反变量。NET(只有接口和委托可以是相反的)。

你的问题的一个可能的解决方案是声明一个反变体接口,如下所示:

interface IPaymentCalculator<in T> // "in" means contravariant
{
    double Calculate(T person);
}

使PaymentCalculator<T>实现IPaymentCalculator<T>接口:

class PaymentCalculator<T> : IPaymentCalculator<T> where T : Person
{
    public double Calculate(T person)
    {
        return 0;    // calculate and return
    }
}

并使Calculators类继承自List<IPaymentCalculator<Person>>

class Calculators : List<IPaymentCalculator<Person>>

有了这些更改,它应该如您所期望的那样工作。

没错。"默认情况下"new MyClass<Derived>()不可分配给new MyClass<Base>()。但是你可以使用接口的协变来完成这个技巧:

class Person { }
class Manager : Person { }
interface IPaymentCalculator<out T> where T : Person
{
}
class PaymentCalculator<T> : IPaymentCalculator<T> where T : Person
{
    public double Calculate(T person)
    {
        return 0;    // calculate and return
    }
}
class Calculators : List<IPaymentCalculator<Person>>
{
    public Calculators()
    {
        this.Add(new PaymentCalculator<Person>());
        this.Add(new PaymentCalculator<Manager>());     // this doesn't work
        PassCalculator(new PaymentCalculator<Person>());
        PassCalculator(new PaymentCalculator<Manager>());   // this doesn't work
    }
    public void PassCalculator(IPaymentCalculator<Person> x)
    { }
}

这将编译并工作。

最新更新