Overloaded functions with inherited parameter

Viewed 44

I'm trying to do something like this but I'm getting an error along the lines of:

Cannot convert from AbstractExampleClass to SpecificExampleClassA.

So I'm probably going in the wrong direction with this code, can anyone tell me what's wrong and how to fix it.

public abstract class AbstractExampleClass 
{
    // Code goes here
}

public class SpecificExampleClassA : AbstractExampleClass 
{

}

public class SpecificExampleClass : AbstractExampleClass 
{

}

public class handler 
{
    public void Handle(AbstractExampleClass aec)
    {
        HandleSpecific(aec);
    }

    public void HandleSpecific(SpecificExampleClassA a)
    {
        // DoSomething
    }

    public void HandleSpecific(SpecificExampleClassB b)
    {
        // DoSomething Else
    }

}
3 Answers

Overloading is resolved at compile time, so you can't expect it to decide which overload to call depending on the runtime type of aec. The overload to call must be decided at compile time.

What you really need here is the "subtyping" kind of polymorphism (aka just "polymorphism" in C# terminology), not ad hoc polymorphism (aka "overloading").

Move the handler methods in the subclasses instead:

public abstract class AbstractExampleClass 
{
    public abstract void Specific();
}

public class SpecificExampleClassA : AbstractExampleClass 
{

    public override void Specific()
    {
        // DoSomething
    }
}

public class SpecificExampleClass : AbstractExampleClass 
{

    public override void Specific()
    {
        // DoSomething Else
    }
}

public class handler 
{
    public void Handle(AbstractExampleClass aec)
    {
        aec.Specific();
    }
}

That can be handled by the Visitor Pattern

public abstract class AbstractExampleClass 
{
    public abstract void Accept( Handler handler );
}

public class SpecificExampleClassA : AbstractExampleClass 
{
    public override Accept( Handler handler )
    {
        handler.HandleSpecific( this );
    }
}

public class SpecificExampleClass : AbstractExampleClass 
{
    public override Accept( Handler handler )
    {
        handler.HandleSpecific( this );
    }
}

public class Handler // the Visitor
{
    public void Handle(AbstractExampleClass aec)
    {
        aec.Accept( this );
    }

    public void HandleSpecific(SpecificExampleClassA a) // visit method
    {
        // DoSomething
    }

    public void HandleSpecific(SpecificExampleClassB b) // visit method
    {
        // DoSomething Else
    }
}

If you really have to do it that way, you can do:

    public void Handle(AbstractExampleClass aec)
    {
        switch (aec)
        {
            case SpecificExampleClassA a:
                HandleSpecific(a);
                break;
            case SpecificExampleClassB b:
                HandleSpecific(b);
                break;
            default:
                throw new Exception($"What do I do with a '{aec?.GetType()}'?");
        }
    }

But I recommend an approach like the one in Sweeper's answer if you are allowed to do that.

Related