简体   繁体   English

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

[英]Generic Implementation of interface with specified type

I have an interesting situation where I'd like to use a base class utilising a type parameter to implement an interface and also keep things DRY with inheriting classes. 我有一个有趣的情况,我想使用一个类类参数的基类来实现一个接口,并保持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
    }
}

Is there something i'm missing with the generic 'where' clause or something? 通用的'where'条款或其他什么东西我缺少什么? In my head this should work. 在我的脑海里,这应该工作。 Or does the compiler need EXACTLY the same implementation as the interface definition? 或者编译器是否需要与接口定义完全相同的实现?

I can't easily move the type parameter into the ICalculator as there are a lot of places that it is used without any requirement for the generic. 我不能轻易地将类型参数移动到ICalculator中,因为有很多地方使用它而不需要通用。

That's cleared things up. 这已经解决了。 Thanks for the info. 谢谢(你的)信息。 Now obviously a solution is to make the interface take the type parameter. 现在显然一个解决方案是使接口采用类型参数。 However ICalculator's are used in a number of places and are referenced just as ICalculator I now get compiler errors if I omit the type parameter in Interfaces that refer to ICalculator... Is there a way to architect this that should work!? 然而ICalculator的用法很多,并且被引用为ICalculator我现在得到编译器错误,如果我省略了引用ICalculator的接口中的类型参数...有没有办法设计这应该工作!?

In my head this should work. 在我的脑海里,这应该工作。

The problem then is in your head! 问题就出在你的头上! :-) This should not work. :-)这不应该工作。 Let's see why. 让我们看看为什么。

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);

And now there is a tiger in the giraffe paddock, and life is good for the tiger but bad for the giraffes. 现在长颈鹿围场里有一只老虎,生活对老虎有好处,但对长颈鹿来说却不好。 That's why this is illegal. 这就是为什么这是非法的。

Or does the compiler need EXACTLY the same implementation as the interface definition? 或者编译器是否需要与接口定义完全相同的实现?

The member which implements an interface member must exactly match the signature of the implemented method. 实现接口成员的成员必须与已实现方法的签名完全匹配。 For example, you cannot use return type covariance: 例如,您不能使用返回类型协方差:

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

The contract requires an animal; 合同要求动物; you provide a giraffe. 你提供长颈鹿。 That should work, logically, but this is not legal in C#. 从逻辑上讲,这应该是有效的,但这在C#中是不合法的。 (It is in C++.) (它是在C ++中。)

See any of the many questions on this site about return type covariance for the reasons why. 请参阅本网站上有关返回类型协方差的任何问题,原因如下。

Similarly for parameter type contravariance: 类似地,参数类型相反:

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

Again, this is logically sensible; 同样,这在逻辑上是合理的; the contract requires that you take a mammal, and this takes any animal. 合同要求你带一个哺乳动物,这需要任何动物。 But again, this is not legal. 但同样,这不合法。

There are some covariant and contravariant operations in C#; C#中有一些协变和逆变操作; see any of numerous questions on those topics on this site, or browse the covariance and contravariance articles on ericlippert.com or my previous msdn blog. 请参阅本网站上有关这些主题的众多问题,或浏览ericlippert.com或我之前的msdn博客上的协方差和逆变文章。

If this worked then you'd be able to say something like this: 如果这样有效,那么你可以说出这样的话:

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

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

That's probably not what you wanted... 这可能不是你想要的......

Your interface says any class implementing it will provide this method: 你的界面说任何实现它的类都会提供这个方法:

void Process(ICalculationModel calculationModel);

Now obviously PipeworkInspections does not . 现在显然PipeworkInspections 没有 It does not have a method Process that accepts any ICalculationModel . 它没有接受任何ICalculationModel的方法Process IT only has a method accepting specific implementations of ICalculationModel . IT只有一个方法接受ICalculationModel 特定实现 So your compilation fails. 所以你的编译失败了。

Yes, you need the exact implementation. 是的,您需要确切的实施。

As an alternative you can make interface and Process method generic if it works for you: 作为替代方案,如果它适用于您,可以使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);
}

I agree with Eric Lippert's response: you can't. 我同意Eric Lippert的回答:你做不到。 And he explained in a very good way why this happens. 他以非常好的方式解释了为什么会这样。

If you really want to do this, you can add the following to your abstract class, and it will compile: 如果你真的想这样做,你可以将以下内容添加到抽象类中,它将编译:

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

But you need to know what you are doing, otherwise you might have some InvalidCastException at runtime. 但您需要知道自己在做什么,否则在运行时可能会出现一些InvalidCastException

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM