Given the following class and interface:
public class Test<T>
{
}
public interface ITesting<T>
{
Test<T> LoadTest();
}
I can add a class with the following:
public class TestManager : ITesting<object>
{
#region ITesting
public Test<object> LoadTest()
{
return new Test<object>();
}
#endregion
}
Which works fine and throws no errors. If I try to replace that class with the following:
public class TestDerived : Test<object>
{
}
public class TestDerivedManager : ITesting<object>
{
#region ITesting
public TestDerived LoadTest()
{
return new TestDerived();
}
#endregion
}
I now get the following error:
Error 'TestDerivedManager' does not implement interface member 'ITesting.LoadTest()'. 'TestDerivedManager.LoadTest()' cannot implement 'ITesting.LoadTest()' because it does not have the matching return type of 'Test'.
But to me it seems like this should work as TestDerived is Test<object>. I'm obviously not understanding something correctly here. Could someone possible point me to details on why this is incorrect? And possibly what I might do to correct it?
The feature you want is called return type covariance. It is a feature of c++ but not of c#, so you'll have to do what the error says.
I recommend you make an explicit interface implementation that calls your public method. That way you get the best of both worlds.
A TestDerived is a Test<object>, yes, but a Test<object> is not a TestDerived.
The contract says that ITesting<object> has a method that can return any Test<object>. Not just one special case (TestDerived).
To make your code work, change it as follows:
public class TestDerivedManager : ITesting<object>
{
public Test<object> LoadTest()
{
return new TestDerived();
}
}
Change the return type of the method back to Test<object> and it should work. The return type is part of the contract when implementing an interface. You can still return the TestDerived since it is a Test<object>.
What you're looking for is called "return type covariance," and unfortunately is not supported by C#. You can't override (or implement) a method with a different return type than the original signature, even if that return type derives from the original return type.
What you can do (which may or may not be a good idea) is implement the interface explicitly and have that call a public method that returns the narrower type you're looking for:
public class TestDerived : Test<object>
{
}
public class TestDerivedManager : ITesting<object>
{
public TestDerived LoadTest()
{
return new TestDerived();
}
Test<object> ITesting<object>.LoadTest()
{
return this.LoadTest();
}
}
That adds an extra layer of complication to your implementation, but it also gives you the public contract you're looking for, along with compatibility with the interface.
Everyone has good technical answer but no one explain why. So I think I will give an illustration about interface.
The general way of interface programming is you should implement the exact method or property described in interface. Let's say that you has interface:
public interface ITesting<T>
{
Test<T> LoadTest();
}
The usage of this interface in your consumer should be like this:
ITesting<object> testingLoader = GetTestingLoader();
Test<object> testingLoader.LoadTest();
If you access the object by using the interface, you don't know the implementation. You only know that the interface ITesting<T> will return Test<T> for the LoadTest() method.
It will come into sense when you see the consumer example above. You (and the compiler) don't (and won't) know that the interface ITesting<object> has a method Test<object> LoadTest() unless you declare it. And what will happen if you try to use an object that is implemented ITesting<object> but has no Test<object> LoadTest() method? It will error won't it?
This is following the LSV principle.
Related
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!?
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.
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. It does not have a method Process that accepts any ICalculationModel. IT only has a method accepting specific implementations of 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:
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. 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.
I'm realizing now that covariance is not available in abstract classes but is there anyway that I can utilize it here so that I can continue with this pattern.
Basically want the ability to create an instance of the first generic argument and pass the object which creates this object itself.
The below will fail at runtime because SpecialProcessor cannot be assigned to ProcessorBase with respect to generic types.
Appreciate any suggestions.
public class ProcessorUser<T> where T : ProcessorBase
{
public void ReceiveCommand()
{
Activator.CreateInstance(typeof (T), this);
}
}
public abstract class ProcessorBase
{
protected ProcessorBase(ProcessorUser<ProcessorBase> param)
{
}
}
public class SpecialProcessor : ProcessorBase
{
public SpecialProcessor(ProcessorUser<ProcessorBase> param)
: base(param)
{
}
}
Actually, from your less-than-complete code example, it's not clear at all a) what you are trying to do, and b) what "fails at runtime". You didn't show any code that calls the ReceiveCommand() method, so it's impossible to see in what way that code might fail.
That said, the usual way to gain access to variance in C# is through delegate or interface types. So you can declare a covariant interface to be implemented by ProcessorUser<T>, and then use that interface in the constructor declarations instead of the actual type. For example:
interface IProcessorUser<out T> where T : ProcessorBase
{
void ReceiveCommand();
}
class ProcessorUser<T> : IProcessorUser<T> where T : ProcessorBase
{
public void ReceiveCommand()
{
Activator.CreateInstance(typeof(T), this);
}
}
abstract class ProcessorBase
{
protected ProcessorBase(IProcessorUser<ProcessorBase> param)
{
}
}
class SpecialProcessor : ProcessorBase
{
private IProcessorUser<SpecialProcessor> _param;
public SpecialProcessor(IProcessorUser<SpecialProcessor> param)
: base(param)
{
_param = param;
}
public void ReceiveCommand() { _param.ReceiveCommand(); }
}
Note that I added the ReceiveCommand() method to the SpecialProcessor class just so I could see something execute at run-time. And that something does in fact work. But there's no way for me to know whether in your scenario, this is what you wanted to happen. You'd have to provide a good, minimal, complete code example that clearly shows what you are trying to do and what difficulty you are having doing it, if you want a clear, precise answer to that aspect of it.
(By the way, this really doesn't have anything to do with abstract classes. There's not even anything in your code example that is actually abstract, other than the class declaration itself, and the general principle applies to any class, not just abstract ones).
I am trying to design an interface, so that it has a generic type of id and a generic method that returns the type of the class that implements this interface. For example:
public interface IEntity <IDType, MethodReturnType>
{
IDType ID {get; set;}
MethodReturnType Get();
}
public class Model : IEntity<int, Model>
{
int ID {get; set; }
Model Get() { // do something }
}
My question is, it seems silly to put in Model as the second type parameter of IEntity, because I am already in a Model's class, it should be some intelligence way to figure out what type it is (although using generic type requires it to be determined before compile time).
Is it any other solution that can help me to get rid of the Model type while retain the Get method definition in the interface?
In this context, there are two typical ways to go about designing your classes and interfaces. I'll stray slightly from your exact example to try to make the answer more general.
Which option to choose really depends on how you want your classes and interfaces to be used.
Option 1
Make your interface generic, so that the interface members have knowledge of the exact type.
public interface IEntity<TDescription>
{
TDescription Get();
}
public class MyModel : IEntity<MyDescription>
{
MyDescription Get() { ... }
}
public class MyDescription { ... }
This means that when you use your interface IEntity<TDescription> you need to know TDescription at the time of use. The benefit is that you get more compile-time type checking.
Option 2
Do not make your interface generic and instead have your interface members use interfaces as well.
public interface IEntity
{
IDescription Get();
}
public interface IDescription { ... }
public class MyModel : IEntity
{
MyDescription Get() { ... }
IDescription IEntity.Get() { return this.Get(); }
}
public class MyDescription : IDescription { ... }
This is more flexible, but it also means less compile-time type checking.
You can determine the inherited class type with this.GetType() but that will not allow you to create generic functions/parameters/etc as you are doing.
So to your answer, no, you can't unless you will not use that type in any way (you can still get the base type of the class and use it but cannot set it as return type/param type/etc).
I'm writing an SDK which has an OOP structure for implementing data types;
first an interface
then an abstract implementation
finally an abstract generic implementation
People can choose to implement either the interface, or derive from either of the classes.
public interface IGoo
{
IGoo Duplicate();
...
}
public abstract class Goo : IGoo
{
IGoo IGoo.Duplicate() {
return Duplicate();
}
abstract public Goo Duplicate();
...
}
public abstract class Goo<T> : Goo
{
abstract public Goo<T> Duplicate(); ??????
...
}
I'd like to re-implement the Duplicate method so that it always returns the most specific type possible. I.e. when you call Duplicate on an IGoo instance, you get another IGoo. If you call it on Goo, you get Goo, if you call it on -say- Goo<int>, you get Goo<int>. And all Duplicate() methods always call the most specific implementation.
Is this possible? Is it only possible when you can implement an interface explicitly? In which case, should I not make Goo<int> derive from Goo, but have it implement IGoo instead and type all the low-level functionality twice?
What about the following?
public interface IObj
{
IObj Duplicate();
}
public abstract class Obj : IObj
{
public Obj()
{
}
public virtual IObj Duplicate()
{
return this;
}
}
public abstract class ObjT<T> : Obj
{
public ObjT()
{
}
public override IObj Duplicate()
{
return this;
}
}
public class ObjImpl : Obj
{
}
public class ObjTImpl : ObjT<int>
{
}
I understand that you want it to return the most specific type possible in any inheriting class but it actually is. It's boxing the inheriting type into the interface (or a raw object if you where to return objects instead of interface types. If you run the following test in a console app you will see the proper type is represented:
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
ObjImpl a = new ObjImpl();
ObjTImpl b = new ObjTImpl();
Console.WriteLine(a.Duplicate().GetType());
Console.WriteLine(b.Duplicate().GetType());
Console.ReadLine();
}
}
}
// outputs:
// ObjImpl
// ObjTImpl
The idea of redefining abstracts of abstracts goes against the purpose of abstract polymorphism. If the derived types do not intend to implement the inherited abstract member, they should not be inheriting it.
Although the example I gave above would require casting to access any child class-specific members, it would be the proper way to do it in this approach. The runtime needs to know what types it should expect to deal with.
There is always dynamics you could play around with but to be honest I haven't played around with dynamics with generics and inheritance as I suspect I would make my compiler cry, and when it cries, I cry, a little bit deep down inside... lol
It is only possible when you implement the interface explicitly. That's because the return type of a method is not part of its signature - which the compiler checks when overloading. Therefore, otherwise identical methods which only differ in their return type are syntactically not possible.
I'm curious to know why the implementation of my interface in the abstract base class does not satisfy the the requirements in sub-classes. Here's an example:
public interface IBase { }
public interface IConcrete : IBase { }
public interface IBaseManager<out T>
where T : IBase
{
T Create();
IEnumerable<T> SelectAll();
}
public interface IConcreteManager : IBaseManager<IConcrete> { }
public abstract class Base : IBase { }
public class Concrete1 : Base, IConcrete { }
public abstract class BaseManager<T> : IBaseManager<T> where T : class, IBase
{
#region IBaseManager<T> Members
public T Create()
{
throw new NotImplementedException();
}
public IEnumerable<T> SelectAll()
{
throw new NotImplementedException();
}
#endregion
}
public class ConcreteManager : BaseManager<Concrete>, IConcereteManager
{
//error occurs here
}
This is the error that is being generated:
'ConsoleApplication4.ConcreteManager' does not implement interface member 'ConsoleApplication4.IBaseManager<ConsoleApplication4.IConcrete>.Create()'.
'ConsoleApplication4.BaseManager<ConsoleApplication4.Concrete>.Create()' cannot implement 'ConsoleApplication4.IBaseManager<ConsoleApplication4.IConcrete>.Create()' because it does not have the matching return type of 'ConsoleApplication4.IConcrete'.
If I add these methods to the ConcreteManager class, everything is fine and the compiler is happy.
public new IConcrete Create()
{
return base.Create();
}
public new IEnumerable<IConcrete> SelectAll()
{
return base.SelectAll();
}
If simply returning what the methods from the base class return is sufficient, why do the methods have to be added? Why can't the compiler call the methods in the base class?
As John points out correctly, the C# language does not support return type covariance. Neither does the CLR, so even if the language supported it, the only way we could actually implement the feature would be to silently generate exactly the code you've had to add yourself.
The small benefit afforded to developers of avoiding having to write those stub methods really does not justify the considerable cost of doing the more general covariance feature, so we've never done it.
It looks like you're assuming return type covariance, since ConcreteManager (as an IConcreteManager) expects both Create() and SelectAll() methods with a return type of IConcrete and IEnumerable<IConcrete> respectively, which the base class does not provide.
You are getting those errors because C# does not support return type covariance.
When you implement an interface/abstract class, you must use the same signature. See here
Don't let the generics throw you off, this is no different than if there were no generics.