2012-09-07 101 views
2

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

代码中标记为“this does not work”的两行不会编译。

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

+3

这个问题太频繁地以太多的方式被问到。我们需要一个“协方差在C#中不能这样工作”的关闭原因:) –

+0

我比另一个问题更喜欢我的问题! (也是我真的很喜欢和欣赏托马斯和ie的答案) – kennethc

回答

1

即使Manager继承自Person,PaymentCalculator<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 
    } 
} 

而且从List<IPaymentCalculator<Person>>

使 Calculators类继承
class Calculators : List<IPaymentCalculator<Person>> 

随着这些变化,它应该按照您的预期工作。

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

在这种情况下,它是反变换,而不是协变(我最初犯了同样的错误...) –

+0

顺便说一句,我们想出了完全相同的解决方案......我无论如何,我会留下我的答案,因为它给出了更多的解释;) –