- Home /
Interface is lost with inheritance. How to solve?
I have an abstract class Skill, from which Character Skill and NPC skill inherit.
I make an interface that requires a TestSkill (Skill skill) But it does not work if then I do TestSkill(Character Skill).
How do i solve this?
Answer by Bunny83 · Oct 21, 2018 at 05:57 PM
This is a matter of covariance / contravariance. Imagine this
public interface IMyInterface
{
TestSkill (Skill skill);
}
public class SomeClass : IMyInterface
{
public TestSkill(Character Skill)
{
}
}
IMyInterface test = new SomeClass();
test.TestSkill(someNonCharacterSkill);
As you can see we create a SomeClass instance which implements our interface. Since the TestSkill method of the interface accepts any "Skill" derived class it can't work with a method which only accepts a Character derived class. The interface however allows passing any Skill. So your TestSkill method does not match the interface definition. You can not assign match a more derived method parameter with a less derived definition from the interface. It only works the other way round. If the interface would require a Character than a class implementing the interface could accept a Skill as parameter since Character is derived from Skill it doesn't matter.
Since your problem description doesn't include any additional information we can't say more about that besides that it's not possible. We have no idea for what you want to use that interface. Your question is too abstract.
I see! I thought it would be possible to do something like this as a work around.
void TestSkill(<T> skill)
I did not get too much in detail because I was just wondering if I should go down a similar road, but I have other ways to do the same.
Thanks :)
Well it's not clear what you actually want to do with that interface. The interface method expects a Skill while your concrete implementation expects a derived class so you can't treat your concrete implementation as this interface. How do you want to use that interface? An interface is an abstraction of a concept. However TestSkill(Skill skill)
is not an abstraction of TestSkill(Character skill)
. You have to keep the data flow direction in $$anonymous$$d. $$anonymous$$ethod parameters can only become more general the more concrete the type gets (or more concrete the more abstract the type gets). However the return type is the other way round. Here an interface method could return an abstract type and the implementation could return a more concrete type
parameter value --> interface parameter --> implementation parameter--> method --> concrete return type --> interface return type --> return value
All those casts need to be possible implicit. Since only upcasting is implicit a type can only get more abstract automatically but never more concrete. By having an abstract parameter type in the interface, the implementation can't have a more concrete type. $$anonymous$$eep in $$anonymous$$d that you can pass anything that is derived from Skill to your interface. So the concrete implementation has to accept a Skill and can not restrict this type to a more concrete type.
We don't know what you want to do so we can't suggest any solution. You presented us a setup that just doesn't work logically.
Answer by Glurth · Oct 21, 2018 at 06:44 PM
Since the CharacterSkill class is derived from the Skill class, you should be able to CAST a CharacterSkill reference into a Skill reference; I'm actually surprised it didn't do this cast automatically.
Here is a manual-cast usage example:
referenceToClassImplementingISkillInterface.TestSkill( (Skill) someCharacterSkillReference);
[Or perhaps you are talking about defining the function, rather than invoking it? In which case.. see bunny's answer- but let me add: I suspect the design-issue may be in requiring a parameter at all. If the TestSkill function is to be defined INSIDE Character AND NPC class definitions (two that contain Skills, but are NOT derived from the Skill class), the function body itself should probably be extracting the appropriate data to "test". ]
No, what doesn't work is the concrete implementation of that TestSkill method which takes a Character and not a Skill. This is not a compatible method signature for this interface.