Первоначальной причиной путаницы является то, что в вашем Run
переопределении C2
является параметром типа - это не класс, называемый C2
. Полезно прояснить это, оставив его как T
в объявлении переопределяющего метода:
public class P2 : P1
{
// Changed type parameter name from C2 to T for clarity
public override void Run<T>(T c)
{
c.c1Prop = 1;
c.c2Prop = 2;
}
}
Это абсолютно эквивалентный код, но яснее, что происходит.
Теперь T
ограничен where T : C1
, как работает c.c1Prop
, но вполне возможно 1018 *, что c
не будет C2
. Например, я мог бы написать:
class OtherC1 : C1 {}
P2 p2 = new P2();
p2.Run(new OtherC1());
Это явно не может работать с вашим текущим кодом - нет c2Prop
в OtherC1
.
Звучит так, как будто вы хотите, чтобы P1
был универсальным, а не Run
методом. Вы могли бы иметь:
public abstract class P1<T> where T : C1
{
public abstract void Run(T c);
}
public class P2 : P1<C2>
{
public override void Run(C2 c)
{
c.c1Prop = 1; //Is recognized
c.c2Prop = 2; //Is NOT recognized and is an error
}
}
Это будет скомпилировано, и весь код будет знать, что вы можете только предоставить C2
(или более производный класс) для P2.Run
. Так что наш предыдущий пример с OtherC1
больше не будет компилироваться (именно этого мы и хотели бы).