Error while generating generic types

I have a method ExecCommand

that takes an argument Command<CommandResult>

. But it fails to build when I try to pass a command with the CommandResult

-extended generic type:

class Program
{
    class CommandResult
    {
    }

    class Command<TResult> where TResult : CommandResult, new()
    {
        internal virtual TResult ParseReply(object reply)
        {
            return new TResult();
        }
        public Action<TResult> CommandCompleteCallback = null;
    }

    class CommandA : Command<CommandResult>
    {
    }

    class CommandResultForB : CommandResult
    {
    }

    class CommandB : Command<CommandResultForB>
    {
        internal override CommandResultForB ParseReply(object reply)
        {
            return new CommandResultForB();
        }
    }

    static Queue<Command<CommandResult>> commandQueue = new Queue<Command<CommandResult>>();

    static void ThreadLoop()
    {
        // This threadloop transmits the first command on the queue to external library when executeNextCommand is set (it using Peek, so the command stays in the queue until the external library calls OnCommandCompleteResponse()
    }
    static void OnCommandCompleteRespose(object reply)
    {
        // called from external library when command is complete
        lock (commandQueue)
        {
            var command = commandQueue.Dequeue();
            if (command.CommandCompleteCallback != null)
                command.CommandCompleteCallback(command.ParseReply(reply));
        }
    }
    static void ExecCommand(Command<CommandResult> command)
    {
        lock (commandQueue)
        {
            commandQueue.Enqueue(command);
            if (commandQueue.Count == 1)
                executeNextCommand.Set();
        }
    }

    static void Main(string[] args)
    {
        ExecCommand(new CommandA());
        ExecCommand(new CommandB()); // <-- this is the offending line
    }
}

      

Any ideas why I am getting the "Unable to convert from CommandB to Command" error? Why is it not possible to automatically CommandResultForB

distinguish the base class CommandResult

?

+3


source to share


2 answers


The reason for this exception is that, by default, shared parameters are not covariant :

Support for this was added in .net 3.5, but you need to define it through the interface and from the keyword:

interface ICommand<out TResult> where TResult : CommandResult, new()
{
   TResult ParseReply(object reply);
}


class Command<TResult> : ICommand<TResult> where TResult 
                       : CommandResult, new()
{}

      

Then you can update your ExecCommand method to expect an interface:



static void ExecCommand(ICommand<CommandResult> command){}

      

After that, your calls ExecCommand

will work find:

static void Main(string[] args)
{
    ExecCommand(new CommandA());
    ExecCommand(new CommandB()); // <-- works now           
}

      

+3


source


If you want to call ExecuteCommand()

with instances of the type CommandB

and still be as generic as possible, use this:

static void ExecCommand<TResult>(Command<TResult> command) 
    where TResult : CommandResult, new()
{
    TResult res = command.ParseReply(null);
}

      



NOTE . This is the answer to your original question. It might help to understand this part of the problem and might help someone else.

+1


source







All Articles