0

If I have the following interfaces and classes:

public interface IPopulationUnit<T>
{
    IPopulationUnit<T> Breed();
}

 public abstract class PopulationUnit<T>:IPopulationUnit<T>
{
    public abstract PopulationUnit<T> Breed();
}

And then I have an implementation

class StringUnit : PopulationUnit<string>
{        
    public override StringUnit Breed()
    {

    }
}

The code doesn't compile because the Breed method does not match the type IPopulationUnit<string> but technically doesn't it? I mean, StringUnit itself is PopulationUnit<string> which itself is IPopulationUnit<string> so I would think it would work.

How can I restrict StringUnit Breed method to only return type StringUnit but obey the inheritance rules?

Eduard Malakhov
  • 1,095
  • 4
  • 13
  • 25
Oninaig
  • 91
  • 10
  • `StringUnit2: PopulationUnit` meets the criteria of the method, but can't be cast to StringUnit. It makes sense that you aren't able to change the method signature like that. You might be able to do something with covariance. – ProgrammingLlama Mar 26 '18 at 16:50
  • https://stackoverflow.com/questions/24561023/overriding-abstract-property-using-more-specified-return-type-covariance – ProgrammingLlama Mar 26 '18 at 16:56
  • I';m getting an error on `public abstract PopulationUnit Breed();` already because it doesn't see that as an `IPopulationUnit`... – oerkelens Mar 26 '18 at 16:56

3 Answers3

1

Oekelens was close... If you really wanted to do this for some strange reason, throw some constraints on it:

public interface IPopulationUnit<T, T1> where T1 : IPopulationUnit<T, T1>
{
    T1 Breed();
}

public abstract class PopulationUnit<T, T1> : IPopulationUnit<T, T1> where T1 : PopulationUnit<T, T1>
{
    public abstract T1 Breed();
}

public class StringUnit : PopulationUnit<string, StringUnit>
{        
    public override StringUnit Breed()
    {
        throw new NotImplementedException();
    }
}

Why doesn't it work like you had it? Because your class must implement the interface as it is declared; including return type. You can return whatever you like - but you must refer to it in the definition the same way that the interface does.

TheSoftwareJedi
  • 34,421
  • 21
  • 109
  • 151
0

This seems to work, adding a T1 to your interface and your abstract implementation:

    public interface IPopulationUnit<T, T1> where T1 : IPopulationUnit<T, T1>
    {
        T1 Breed();
    }

    public abstract class PopulationUnit<T> : IPopulationUnit<T, PopulationUnit<T>>
    {
        public abstract PopulationUnit<T> Breed();
    }

    class StringUnit : PopulationUnit<string>
    {
        public override PopulationUnit<string> Breed()
        {
            return new StringUnit();
        }
    }

I'm still getting an error if I define the override as StringUnit Breed() (saying it has to return PopulationUnit<string> in order to override Breed()) but you can actually return a StringUnit nonetheless from teh method itself.

oerkelens
  • 5,053
  • 1
  • 22
  • 29
0

The return types in the definition must match the interface exactly.

However you are free to return anything which implements that interface:

public abstract class PopulationUnit<T>:IPopulationUnit<T>
{
    public abstract IPopulationUnit<T> Breed();
}

class StringUnit : PopulationUnit<string>
{        
    public override IPopulationUnit<string> Breed()
    {
        return new StringUnit(); 
    }
}