简体   繁体   中英

Implementing interface member with arguments that are more derived than in those in the interface declaration?

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?

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, eg

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.
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM