2

I have the following interfaces

    public interface IPrice
    {
        int Price { get; }
    }

    public interface IGear : IPrice
    {
        GearUpgrade Upgrades { get; }
    }

and the following classes

    public class GearUpgrade : IPrice
    {
        public int Price
        {
            get { return price; }
            set { price = value; }

        }
    }

    public class ArmorUpgrade : GearUpgrade
    {
    }

    public class ShieldUpgrade : GearUpgrade
    {
    }

    public class WeaponUpgrade : GearUpgrade
    {
    }

So when I try to implement an IGear like this...

    public class Armor : IGear
    {
        private int price = 0;
        public int Price { get => price; }

        private ArmorUpgrade upgrades;
        public ArmorUpgrade Upgrades
        {
            get { return upgrades; }
            set { upgrades = value; }
        }

    }

I get the following error:

'Armor' does not implement interface member 'IGear.Upgrades'. 'Armor.Upgrades' cannot implement 'IGear.Upgrades' because it does not have the matching return type of 'GearUpgrade'.

I figured that if Upgrades is from a subclass of GearUpgrade, the interface should be fulfilled, but apparently it is not... Did I make a false assumption?

5
  • 3
    It looks like you want IGear to be generic. Commented Aug 26, 2020 at 19:32
  • Not sure what would you say that. I have a class Armor, Weapon and Shield. I figured interfaces would be a good abstraction for it. Would you recommend me another implementation, and its advantages? Commented Aug 26, 2020 at 19:34
  • This might be because of the example used not being real code, but in case it is: a gear certainly isn't a price, in any case, a gear has a price Commented Aug 26, 2020 at 19:37
  • @EnriqueMorenoTent because it looks like what you are asking for as code in the question shows different return types... which can be perfectly done with generics. Indeed it is very unlikely useful to whatever you actually trying to achieve, but that is not in the question at all. Commented Aug 26, 2020 at 19:38
  • for those who care, this problem is because c# doesn't have covariant return types. There is a proposal to add that here infoq.com/news/2020/01/CSharp-Covariant-Return-Types Commented Aug 26, 2020 at 19:40

1 Answer 1

4

In order to implement the interface, the method signatures have to match exactly: C# doesn't apply covariance and contravariance implicitly.

Here's a simple fix to allow Armor to implement the IGear interface without messing with the class:

public class Armor : IGear
{
    private int price = 0;
    public int Price { get => price; }

    private ArmorUpgrade upgrades;
    public ArmorUpgrade Upgrades
    {
        get { return upgrades; }
        set { upgrades = value; }
    }

    GearUpgrade IGear.Upgrades => this.Upgrades;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Interesting. This solution seems the more elegant.
@EnriqueMorenoTent Well generic would be much more elegant
@Franck: That probably depends on how much you know about your IGear when you're trying to use it. If all you know is that it's "Gear", then you probably aren't going to be casting it as IGear<ArmorUpgrade>: at that point you're just as well casting it to Armor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.