Search code examples
c#command-pattern

Type error in command pattern


I am trying to implement a command pattern with strongly typed input and output parameters for the command itself.

First of all I have created two interfaces that marks the input and the output for the command:

interface IRequest { }
interface IResponse { }

Then I have created the base classes and interfaces. This is the abstract receiver

interface IReceiver<TRequest, TResponse>
    where TRequest : IRequest
    where TResponse : IResponse
{
    TResponse Action( TRequest request );
}

and this the abstract command

abstract class AbstractCommand<TRequest, TResponse>
    where TRequest : IRequest
    where TResponse : IResponse
{
    protected IReceiver<TRequest, TResponse> _receiver;

    public AbstractCommand( IReceiver<TRequest, TResponse> receiver ) {
        _receiver = receiver;
    }

    public abstract TResponse Execute( TRequest request );
}

Now I am trying to use these objects and so I have created the needed concrete classes

class TypeARequest : IRequest
{
    public TypeARequest() {
    }

    public int NumericValueA { get; set; }
    public int NumericValueB { get; set; }
}

class TypeAResponse : IResponse
{
    public TypeAResponse() {
    }

    public int Result { get; set; }
}

class SumCommand : AbstractCommand<TypeARequest, TypeAResponse>
{
    public SumCommand( IReceiver<TypeARequest, TypeAResponse> receiver ) : base( receiver ) {
    }

    public override TypeAResponse Execute( TypeARequest request ) {
        return _receiver.Action( request );
    }
}

class SumReceiver : IReceiver<TypeARequest, TypeAResponse>
{
    public TypeAResponse Action( TypeARequest request ) {
        return new TypeAResponse() { Result = request.NumericValueA + request.NumericValueB };
    }

}

Finally I have created a CommandProcessor class which should be able to process multiple commands altogether

class CommandProcessor
{
    IList<AbstractCommand<IRequest, IResponse>> _supportedCommands = new List<AbstractCommand<IRequest, IResponse>>();

    public CommandProcessor() {
    }

    void AddSupportedCommand( AbstractCommand<IRequest, IResponse> item ) {
        _supportedCommands.Add( item );
    }

    void SetupSupportedCommands() {
        // ERROR HERE 
        AddSupportedCommand( new SumCommand( new SumReceiver() ) );
    }

}

However I am getting a compile time error saying:

Argument 1: cannot convert from 'SumCommand' to 'AbstractCommand'

Any help or suggestion?


Solution

  • You should create an interface and mark your generic parameter as covariance example:

    interface IRequest { }
    interface IResponse { }
    interface IReceiver<in TRequest, out TResponse>
        where TRequest : IRequest
        where TResponse : IResponse
    {
        TResponse Action(TRequest request);
    }
    
    interface ICommand<out TRequest, out TResponse>
    {
    
    }
    
    abstract class AbstractCommand<TRequest, TResponse> : ICommand<TRequest, TResponse>
        where TRequest : IRequest   
        where TResponse : IResponse
    {
        protected IReceiver<TRequest, TResponse> _receiver;
    
        public AbstractCommand(IReceiver<TRequest, TResponse> receiver)
        {
            _receiver = receiver;
        }
    
        public abstract TResponse Execute(TRequest request);
    }
    
    class CommandProcessor
    {
        IList<ICommand<IRequest, IResponse>> _supportedCommands = new List<ICommand<IRequest, IResponse>>();
    
        public CommandProcessor()
        {
        }
    
        void AddSupportedCommand(ICommand<IRequest, IResponse> item)
        {
            _supportedCommands.Add(item);
        }
    
        void SetupSupportedCommands()
        {
            AddSupportedCommand(new SumCommand(new SumReceiver()));
        }
    
    }
    

    More information here out modifier msdn