1

I derive a bunch of models from a base model class. Here is an example of one such child model:

namespace MyProject.Models
{
    public abstract class Parent1 {}
}

namespace MyProject.Models
{
    public class Child1: Parent1  { ... }
}

Each of these models has pretty consistent functionality, which I code in separate classes I call "handlers." There is a base handler, to define the method names:

namespace MyProject.Models
{
    public abstract class Parent1Handler
    {
        public abstract void Update(Parent1 model);
    }
}

But when I try to create a derived handler, .NET is unhappy with my parameter type:

namespace MyProject.Models
{
    public class Child1Handler: Parent1Handler
    {
        public override void Update(Child1 model) { ... }
    }
}

It essentially demands that I use an argument of type Parent1 to override my method. But Child1 is derived from Parent1; shouldn't an argument of type Child1 be a suitable stand-in?

3
  • 2
    It is not, because this is not how overriding works. Check docs -> You must provide exact same declaration of the function. What if the base class have 2 methods Update(Parent1 model) and Update(Child1 model) -> should the overriden method override the 1st or 2nd? Among others, that is the reason why it must be exactly same. Commented Jan 25, 2021 at 19:59
  • 1
    What exactly is your question? "shouldn't an argument of type Child1 be a suitable stand-in?" - is that what you want to know? Commented Jan 25, 2021 at 20:07
  • 1
    You could use generic types, also maybe look into interfaces and read about covariance and contravariance. Since your ChildHandler IS by definition also a ParentHandler, it can't provide more specific behavior than its base class. Just not possible by design. Imagine having a List<ParentHandler> and calling the method Update(...) with a ParentModel - what should happen if a ParentHandler is in that list? Commented Jan 25, 2021 at 20:09

1 Answer 1

1

As commenters have noted, that's not how overriding works. You can't change the signature of an overridden method at all. You could pass an instance of Child1 into your overridden Update method, but you can't change the signature.

To get at what it seems like you want to do, you'll have to leverage generics

public class Parent1Handler<TChild> where TChild : Parent1
{
    public abstract void Update(TChild model);
}
public class Child1Handler: Parent1Handler<Child1>
{
    public override void Update(Child1 model) 
    {
     ....
    }
}

This allows you to have a separate child Handler for each inherited model. However, I would check yourself and make sure that this is really what you want to be doing. Model inheritance can be a trap. It can facilitate code reuse, but it can also quickly lead to nightmares where it's difficult to figure out where specific pieces of logic are. If you are going to inherit models, I'd strongly encourage you not to go more than one layer deep.

Sign up to request clarification or add additional context in comments.

2 Comments

Huh. My experiments are still green, but it is looking like you took this in the direction of what I was trying to achieve. Thank you muchly. Side question: is there literature you can recommend for grokking the way that polymorphism works in .NET?
When in doubt, pick up a copy of C# in Depth by Jon Skeet. It's a full book, but it covers pretty much every topic about the language and framework.

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.