Search code examples
c#inheritancedesign-patternscqrs

Inheritance: Unable to access method from base class


I am implementing CQRS pattern. To use CQRS pattern in my project I wrote three commands, they are

public class DogCommand : PetCommand
{
    public DogCommand(){}
    public override string Name{get; set;}
}

public class CatCommand : PetCommand
{
    public CatCommand(){}
    public override string Name{get; set;}
}

public abstract class PetCommand : ICommand
{
    public PetCommand(){}
    public virtual string Name{get; set;}
}

public interface ICommand
{
   //Business logic
 }

Here I have interface called ICommand. PetCommand is base class which is implementing this interface. Derived class DogCommand and CatCommand are inheriting PetCommand.

I also wrote base command handler, as below

public abstract class BaseCommandHandler<T> : CommandHandler<T> where T : ICommand
{
    protected BaseCommandHandler(string type, string name): base(type, name)
    {

    }
}
public abstract class CommandHandler<T> : ICommandHandler<T> where T : ICommand
{
   protected CommandHandler(string type, string name)
   {
    //Business logic
   }

   protected void LogWrite(T command)
   {
      //Writing log 
   }
}


public interface ICommandHandler<in T> where T : ICommand
{
    void Run(T command);
}

All functions present in BaseCommandHandler, I will use in each derived command handler

Now problem is in derived class command handler

public class PetCommandHandler : BaseCommandHandler<DogCommand>, ICommandHandler<CatCommand> 
{

    public void Run(DogCommand dCommand)
    {
        this.LogWrite(dCommand)      
    }

    public void Run(CatCommand cCommand)
    {
       **//Want to access this.LogWrite() with cCommand. How can I do that?**          
    }
}

Here I am unable to access this.LogWrite() function for cCommand, because PetCommandHandler is inheriting first BaseCommandHandler and then implementing ICommandHandle.

How to access this.LogWrite() function for cCommand?

Here is compile time error:

cannot convert from ‘Command.DogCommand’ to ‘Command.CatCommand’


Update :

First way to fix this issue :

I can fix this issue by using base command i.e PetCommand in BaseCommandHandler instead of DogCommand. This will help me to access all derived classes in this.LogWrite() function, but this will lead me to implement empty Run(PetCommand petCommand) {} function, that I don't want to do.

Second way :

I can change LogWrite() function as virtual in CommandHandler and override whenever I face this situation.

I really appreciate if someone provide me any other solution for this issue.


Solution

  • You have a design issue to resolve.

    You are trying to handle Two separate Types in the generic class. This is not a extensible design.

    When there will be a new class inheriting from PetCommand created, you will have to change PetCommand handler class to implement interface ICommandHandler<newPetCommand>. That's basically a bad design.

    The command handler class of yours should deal with the Pet, not with a specific type of Pet such as Cat or Dog.

    You need to have CommandHandler and PetCommandHandler class as following.

    public abstract class CommandHandler<T> : ICommandHandler<T> where T : ICommand
    {
        protected CommandHandler(string type, string name)
        {
            //Business logic
        }
    
        //Making Run method abstract so that 
        //individual Handler class can have their own logic in it.
        public abstract void Run(T command);
    
        //Common implementation for LogWrite.
        //If this also requires override, it can be made virtual 
        //so that deriving class can override the logic.
        protected void LogWrite(T command)
        {
            //Writing log 
        }
    }
    
    //PetCommandHandler class now can be used for any class object 
    //which is inheriting PetCommand class.
    public class PetCommandHandler<T> : BaseCommandHandler<T> where T: PetCommand
    {
        public PetCommandHandler(string type, string name) : base(type, name)
        {
    
        }
    
        public override void Run(T dCommand)
        {
            this.LogWrite(dCommand);
        }
    }
    

    How to test?

    var dog = new DogCommand();
    var commandHandler = new PetCommandHandler<DogCommand>("Dog", "Tom");
    commandHandler.Run(dog);
    
    var cat = new CatCommand();
    var catHandler = new PetCommandHandler<CatCommand>("Cat", "Mini");
    catHandler.Run(cat);
    

    If you later introduce new PetCommand class, let say PandaCommand. You can still use PetHandler as following.

    var pandaHandler = new PetHandler<PandaCommand>("Panda", "Po");
    var panda = new PandaCommand();
    pandaHandler.Run(panda);
    

    If you do not want to create separate instance of PetCommandHandler for different PetCommand type. You can change the PetCommandHandler class as following.

    public class PetCommandHandler : BaseCommandHandler<PetCommand>
    {
        public PetCommandHandler(string type, string name) : base(type, name)
        {
    
        }
        public override void Run(PetCommand dCommand)
        {
            this.LogWrite(dCommand);
        }
    }
    

    With this class you just need to create only one instance of PetCommndHandler and you can execute Run method with any object of PetCommand

    var patCommandHandler = new PetCommandHandler("someType", "someName");
    patCommandHandler.Run(dog);
    patCommandHandler.Run(cat);
    patCommandHandler.Run(panda);
    

    I hope this will help you resolve your issue.