具有指定类型

时间:2016-02-17 17:12:25

标签: c# generics inheritance

我有一个有趣的情况,我想使用类型参数的基类来实现接口,并使用继承类来保持DRY。

public interface ICalculator
{
    void Process(ICalculationModel calculationModel);
}

public abstract class CalculatorBase<T> :ICalculator where T : ICalculationModel
{
     // Compiler moans that Process(ICalculationModel calculationModel) isn't implemented
     public abstract void Process(T calculationModel);
}

public class PipeworkInspections : CalculatorBase<GasSafetyModel>
{
    public override void Process(GasSafetyModel documentModel){
        //snip
    }
}

通用&#39;其中&#39;是否缺少某些东西?条款或什么?在我的脑海里,这应该工作。或者编译器是否需要与接口定义完全相同的实现?

我无法轻松地将类型参数移动到ICalculator中,因为有很多地方使用它而不需要通用。

这已经解决了问题。谢谢(你的)信息。现在显然一个解决方案是使接口采用类型参数。但是ICalculator在许多地方被使用,并被引用为ICalculator如果我省略了引用ICalculator的接口中的类型参数,我现在得到编译器错误......有没有办法设计这个应该工作!?

5 个答案:

答案 0 :(得分:8)

  

在我的脑海里,这应该有效。

问题就在你脑海中! :-)这不应该工作。让我们看看为什么。

interface ICage
{
    void Enclose(Animal animal);
}
class ZooCage<T> : ICage where T : Animal
{
    public void Enclose(T t) { ... }
}
...

var giraffePaddock = new ZooCage<Giraffe>();
var cage = (ICage)giraffePaddock;
var tiger = new Tiger();
icage.Enclose(tiger);

现在长颈鹿围场里有一只老虎,老虎的生活虽然好,但对长颈鹿却不好。这就是为什么这是非法的。

  

或者编译器是否需要与接口定义完全相同的实现?

实现接口成员的成员必须与已实现方法的签名完全匹配。例如,您不能使用返回类型协方差:

interface I
{
    Animal GetAnimal();
}
class C : I
{
    public Giraffe GetAnimal() { ... } // not legal.
}

合同要求动物;你提供长颈鹿。从逻辑上讲,这应该是有效的,但这在C#中是不合法的。 (它是用C ++编写的。)

请参阅本网站上有关返回类型协方差的任何问题,原因如下。

类似于参数类型的逆转:

interface I
{
    void PutMammal (Mammal mammal);
}
class C : I
{
    public PutMammal(Animal animal) { ... } // not legal.
}

同样,这在逻辑上是合理的;合同要求你带一个哺乳动物,这需要任何动物。但同样,这不合法。

C#中有一些协变和逆变操作;请参阅本网站上有关这些主题的众多问题,或浏览ericlippert.com或我以前的msdn博客上的协方差和逆转文章。

答案 1 :(得分:0)

如果这样有效,那么你可以说出这样的话:

PipeworkInspections pipeworks = new PipeworkInspections();
ICalculator calculator = pipeworks;

NuclearPowerSafetyModel nuclearModel = new NuclearPowerSafetyModel();
calculator.Process(nuclearModel); // <-- Oops!

这可能不是你想要的......

答案 2 :(得分:0)

您的界面说任何实现它的课程提供此方法:

void Process(ICalculationModel calculationModel);

现在显然PipeworkInspections 。它没有接受任何Process的方法ICalculationModel。 IT只有一种方法接受 ICalculationModel的具体实施方法。所以你的编译失败了。

答案 3 :(得分:0)

是的,您需要确切的实施。

作为替代方案,如果适用于您,则可以interfaceProcess方法通用:

public interface ICalculator<T> where T : ICalculationModel
{
    void Process(T calculationModel);
}

public abstract class CalculatorBase<T> : ICalculator where T : ICalculationModel
{
    public abstract void Process(T calculationModel);
}

答案 4 :(得分:0)

我同意Eric Lippert的回应:你不能。他以非常好的方式解释了为什么会这样。

如果确实想要这样做,您可以将以下内容添加到抽象类中,它将编译:

void ICalculator.Process(ICalculationModel calcMod)
{
   Process((T)calcMod);
}

但是你需要知道你在做什么,否则你可能在运行时有一些InvalidCastException