Giles Morris Giles Morris - 2 months ago 12
C# Question

Cannot pass derived class to method that accepts generic base class

Broadly i have the following code...

using System;

public interface ICommand<in TArgs>
where TArgs : BaseArgs
{
void Execute();
void Execute(TArgs args);
}

public class BaseArgs
{ }

public abstract class BaseCommand<TArgs> : ICommand<TArgs>
where TArgs : BaseArgs
{
public void Execute()
{
var args = this.CreateArgs();
this.Execute(args);
}

public void Execute(TArgs args)
{
this.GetData(args);
}

protected abstract void GetData(TArgs args);
protected abstract TArgs CreateArgs();
}

public class ActualArgs : BaseArgs
{ }

public class ActualCommand : BaseCommand<ActualArgs>
{
protected override void GetData(ActualArgs args)
{
var messenger = new Messenger(this.Execute);
var m2 = new Messenger2(this);
}

protected override ActualArgs CreateArgs()
{
return new ActualArgs();
}
}

public class Messenger
{
public Messenger(Action caller)
{
caller();
}
}

public class Messenger2
{
public Messenger2(BaseCommand<BaseArgs> caller)
{
caller.Execute();
}
}


Ideally i'd like to use Messenger2 but the line in the ActualCommand complains that it cant cast ActualCommand to BaseCommand, i'd really rather not declare Messenger2 as

new Messenger2<ActualCommand<ActualArgs>>(this)


thanks in advance

Answer

This doesn't work for two reasons:

  1. Only generic interfaces can be made covariant (or contravariant). Your parameter is the abstract base class, not the interface.
  2. Your interface is not (and cannot) be covariant.

Suppose this actually compiled - you'd be allowed to do this:

BaseCommand<BaseArgs> command = new ActualCommand();

command.Execute(new SomeOtherArgsDerivedFromBaseArgs());

This must give you some exception, as ActualCommand has no idea how to handle anything other than something that is or can be cast to ActualArgs.

Comments