Is there a way to implement this so that I can use overloaded methods with more derived arguments? The overloaded methods aren't matching the signature as defined in the interface, even though they inherit from the Command
class, but they should still be interchangeable, right?
public class Command {}
public interface IHandler
{
public Result Handle(Command cmd);
}
public class CommandOne : Command {}
public class CommandTwo : Command {}
public class HandlerA: IHandler
{
public Result Handle(CommandOne cmd) {...}
public Result Handle(CommandTwo cmd) {...}
}
I suppose this is not allowed since it would allow you to do this which doesn't make sense:
public class CommandThree : Command {}
public class HandlerB: IHandler
{
public Result Handle(CommandOne cmd) {...}
public Result Handle(CommandThree cmd) {...}
}
IHandler handler = new HandlerA();
handler.Handle(new CommandThree()); // this is not defined
But is there a way to get around this like implementing a default method that would get called if there is no matching signature? Like so:
public class HandlerC: IHandler
{
public Result Handle(CommandOne cmd) {...}
public Result Handle(CommandTwo cmd) {...}
public Result Handle(Command cmd) {...}
}
This compiles but will lead to a NotImplementedException
when I try to call the Handle method with any derived class. I'm assuming this is because the interface only has that one method with the signature using the Command
class.
IHandler handler = new HandlerC();
handler.Handle(new Command()); // works
handler.Handle(new CommandOne()); //NotImplementedException
Is there even a way to get this to work?
CodePudding user response:
You must implement the interface as it is declared, so you must declare a method with a parameter of the base class type. You can overload the method with parameters of more specific types though. Only the interface method can be called via a reference of the interface type, but you can implement that method such that it calls the other overloads if the argument is the appropriate type, e.g.
public class HandlerD : IHandler
{
public Result Handle(CommandOne cmd) { /* ... */ }
public Result Handle(CommandTwo cmd) { /* ... */ }
public Result Handle(Command cmd)
{
if (cmd is CommandOne cmd1)
{
return Handle(cmd1);
}
if (cmd is CommandTwo cmd2)
{
return Handle(cmd2);
}
// Default implementation here.
}
}