【问题标题】:Generic type of a class cannot accept generic type of derived type of the class [duplicate]类的泛型类型不能接受类的派生类型的泛型类型[重复]
【发布时间】:2012-09-08 02:31:23
【问题描述】:

可能重复:
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)
    { }
}

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

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

【问题讨论】:

  • 这个问题被问得太频繁了,有太多不同的变体。我们需要一个“协方差在 C# 中不能以这种方式工作”的关闭原因:)
  • 我比其他问题更喜欢我的问题! (我也非常喜欢和感谢 Thomas 和 ie 的回答。)

标签: c#


【解决方案1】:

即使 Manager 继承自 PersonPaymentCalculator&lt;Manager&gt; 也不会继承自 PaymentCalculator&lt;Person&gt;。如果 PaymentCalculator&lt;T&gt;contravariant,它会起作用,但类在 .NET 中不能是逆变的(只有接口和委托可以是逆变的)。

解决您的问题的一种可能方法是声明一个逆变接口,如下所示:

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

使PaymentCalculator&lt;T&gt; 实现IPaymentCalculator&lt;T&gt; 接口:

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

并使Calculators类继承自List&lt;IPaymentCalculator&lt;Person&gt;&gt;

class Calculators : List<IPaymentCalculator<Person>>

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

【讨论】:

    【解决方案2】:

    没错。 “默认情况下”new MyClass&lt;Derived&gt;() 不可分配给 new MyClass&lt;Base&gt;()。但是您可以使用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)
        { }
    }
    

    这将编译并工作。

    【讨论】:

    • 在这种情况下,它是逆变,而不是协方差(我最初犯了同样的错误......)
    • 顺便说一句,我们想出了完全相同的解决方案......我还是会留下我的答案,因为它提供了更多解释;)
    猜你喜欢
    • 2014-03-22
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 2011-10-09
    • 2015-01-26
    • 2011-05-24
    相关资源
    最近更新 更多