DaveD
DaveD

Reputation: 2255

Base class used as an abstract method's parameter?

I'm trying to setup some classes like:

public abstract class AnimalBase {      
  public string SpeciesName { get; private set; }

  public AnimalBase(string speciesName) {
    this.SpeciesName = speciesName;
  }

  public abstract void CopyFrom(AnimalDefaultClass defaultVals);
}

public class Mammal : AnimalBase {
  public bool WalksUpright { get; private set; }

  public Mammal(string speciesName) : base(speciesName) {
    this.CopyFrom(new MammalDefaultClass(speciesName));
  }

  public override void CopyFrom(MammalDefaultClass defaultVals) {
    this.WalksUpright = defaultVals.WalksUpright;
  }

  public void Cripple() {
    this.WalksUpright = false;
  }
}

public class MammalDefaultClass : AnimalDefaultClass {
  public bool WalksUpright { get; private set; }

  public MammalDefaultClass(string speciesName) {
    using (var dataStore = theoreticalFactory.GetDataStore()) {
      this.WalksUpright = dataStore[speciesName].WalksUpright;
    }
  } 
}

Obviously that's not quite what I'm trying to accomplish, but the idea is:

Those AnimalDefaultClass derivatives exist because each class of Animal will have different properties, but by definition there will always be a class capable of getting those values for any Animal.

My problem is:

That overridden version of CopyFrom(MammalDefaultClass) isn't being recognized as a valid override of the abstract CopyFrom(AnimalDefaultClass), even though MammalDefaultClass inherits from AnimalDefaultClass

Is it possible to specify a base class as an abstract member's parameter? Is there a simple* workaround? Or is this whole thing just laid out wrong?

-edit: my resolution- After playing around some with MWB and sza's suggestions, I ended up having each subclass implement the method using the base parameter and then cast the input as appropriate, something like:

public class Mammal : AnimalBase {
  ...

  // implements the abstract method from the base class:
  public override void CopyFrom(AnimalDefaultClass defaultVals) {
    this.CopyFrom((MammalDefaultClass)defaultVals);
  }

  public void CopyFrom(MammalDefaultClass defaultVals) {
    this.WalksUpright = defaultVals.WalksUpright;
  }
}

This solution forces me to always implement a CopyFrom(AnimalDefaultClass) , which was the point of the putting the abstract method in the base class in the first place.

Upvotes: 1

Views: 1254

Answers (2)

zs2020
zs2020

Reputation: 54514

I think you can try Abstract Factory pattern. Basically you want to handle some construction logic during the creating the object, and for each different subtype of the Product, you can do differently.

public abstract class AnimalBase
{
    public string SpeciesName { get; private set; }

    protected AnimalBase(string speciesName)
    {
        this.SpeciesName = speciesName;
    }
}

public class Mammal : AnimalBase
{
    public bool WalksUpright { get; set; }

    public Mammal(string speciesName) : base(speciesName)
    {
    }

    public void Cripple()
    {
        this.WalksUpright = false;
    }
}

public interface IAnimalFactory<T> where T : AnimalBase
{
    T CreateAnAnimal(string speciesName);
}

public class MammalFactory: IAnimalFactory<Mammal>
{
    public Mammal CreateAnAnimal(string speciesName)
    {
        var mammal = new Mammal(speciesName);
        var mammalDefault = new MammalDefaultClass(speciesName);
        mammal.WalksUpright = mammalDefault.WalksUpright;
        return mammal;
    }
}

And when you want to create a sub-typed object, you can do e.g.

var mammalFactory = new MammalFactory();
var bunny = mammalFactory.CreateAnAnimal("Bunny");

Upvotes: 2

MWB
MWB

Reputation: 171

So it turns out that even though MammalDefaultClass is a subclass of AnimalDefaultClass, you cannot override a function that takes an AnimalDefaultClass with one that takes a MammalDefaultClass.

Consider this block of code:

public class Dinosaur : AnimalDefaultClass;
Dinosaur defaultDinosaur;

public void makeDinosaur(AnimalDefaultClass adc)
{
    adc.CopyFrom(defaultDinosaur);
}

MammalDefaultClass m;
makeDinosaur(m);

In this case MammalDefaultClass is a subclass of AnimalDefaultClass, so m can be passed to makeDinosaur as adc. Furthermore the CopyFrom for an AnimalDefaultClass only needs another AnimalDefault class, so I can pass in a dinosaur. But that class is actually a Mammal, and so needs a MammalDefaultClass, which dinosaur is not.

The work around would be to take the original type signature and throw an error if the argument is the wrong type (similar to how arrays act in Java).

Upvotes: 1

Related Questions