Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

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? 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.

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!?

like image 256
Ben Ford Avatar asked Feb 17 '16 17:02

Ben Ford


People also ask

What is a generic interface?

A generic interface is primarily a normal interface like any other. It can be used to declare a variable but assigned the appropriate class. It can be returned from a method. It can be passed as argument. You pass a generic interface primarily the same way you would an interface.

Can we use generic in interface?

8. Java Generic Classes and Subtyping. We can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses.

How do you declare a generic interface?

You can declare variant generic interfaces by using the in and out keywords for generic type parameters. ref , in , and out parameters in C# cannot be variant. Value types also do not support variance. You can declare a generic type parameter covariant by using the out keyword.


1 Answers

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#. (It is in 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#; 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.

like image 159
Eric Lippert Avatar answered Sep 20 '22 18:09

Eric Lippert