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

时间:2012-09-07 18:14:33

标签: c#

  

可能重复:
  Casting List<> of Derived class to List<> of base class

标题可能没有多大意义。见代码:

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)
    { }
}

代码中的两行标记为&#34;这不起作用&#34;不会编译。

我可以解决这个问题,但看起来我的意图并不错。或者,是吗?

2 个答案:

答案 0 :(得分:1)

这是对的。 “默认情况下,”new MyClass<Derived>()无法分配给new MyClass<Base>()。但你可以使用co-variance of interfaces

来做到这一点
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)
    { }
}

这将编译和工作。

答案 1 :(得分:1)

即使Manager继承自PersonPaymentCalculator<Manager>也不会继承PaymentCalculator<Person>。如果PaymentCalculator<T>contravariant,它将起作用,但.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>>

通过这些更改,它应该按预期工作。