具有指定类型的接口的通用实现

Ben*_*ord 5 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
    }
}
Run Code Online (Sandbox Code Playgroud)

通用的'where'条款或其他什么东西我缺少什么?在我的脑海里,这应该工作.或者编译器是否需要与接口定义完全相同的实现?

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

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

Eri*_*ert 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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

interface I
{
    Animal GetAnimal();
}
class C : I
{
    public Giraffe GetAnimal() { ... } // not legal.
}
Run Code Online (Sandbox Code Playgroud)

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

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

类似地,参数类型相反:

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

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

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


Sea*_*ean 0

如果这有效,那么你就可以这样说:

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

NuclearPowerSafetyModel nuclearModel = new NuclearPowerSafetyModel();
calculator.Process(nuclearModel); // <-- Oops!
Run Code Online (Sandbox Code Playgroud)

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