0

I have a CommandHandler in my application that has a generic type argument called TCommand. This generic has a restriction: TCommand : ICommand.

I have a test project where I test all my commandhandlers. There is an abstract test class for each command handler with some basic (required) functionality. It has a generic type argument called TCommandHandler. This generic has a restriction as well: TCommandHandler : ICommandHandler<ICommand>. Sadly, I can't get this to work because the argument I provide does not meet this restriction.

This is my example:

public interface ICommand
{ }

public class Command : ICommand
{ }

public interface ICommandHandler<in TCommand> where TCommand : ICommand
{
    Task HandleAsync(TCommand command);
}   

public class ExampleCommand : ICommand
{ }

public class ExampleCommandHandler : ICommandHandler<ExampleCommand>
{
    //Implementation..
}

Below is my test code:

// Base test class
public abstract class BaseCommandHandlerTest<TCommandHandler> 
        where TCommandHandler : ICommandHandler<ICommand>
{
    // Stuff here
}

public ExampleCommandHandlerTest : BaseCommandHandlerTest<ExampleCommandHandler>
{
    // Tests here
}

ExampleCommandHandlerTest gives me the following error:

The type 'ExampleCommandHandler' cannot be used as type parameter 'TCommandHandler' in the generic type or method 'BaseCommandHandlerTest<TCommandHandler>'. There is no implicit reference conversion from 'AddDecoupledBijlageCommandHandler' to 'ICommandHandler<ICommand>'.

My argument DOES inherit from ICommandHandler, and the argument's argument (ExampleCommand) DOES inherit from ICommand.

Can someone tell me what I am doing wrong here and how I could fix this?

If I can't get it fixed, I will just use a where TCommandHandler : class constraint because it is not SUPER important; it is merely test code.

S. ten Brinke
  • 2,557
  • 4
  • 25
  • 50
  • @PosterWhoDeletedWhatI'mCommentingOn This doesn't have anything to do with SQL. It's this kind of 'where' https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint – Dillon Flohr Nov 21 '18 at 15:11
  • The interface is contravariant, not covariant. The generic argument can only be made more *specific*, not more general. – Servy Nov 21 '18 at 15:13
  • 1
    Try `public class ExampleCommandHandler : ICommandHandler` – Miamy Nov 21 '18 at 15:17
  • I once made a pretty deep analysis of convariance and contravariance. You may find it helpful: https://stackoverflow.com/a/53134957/672018 – Andrzej Gis Nov 21 '18 at 15:20
  • @Miamy Hello! Thank you for your reply. Sadly, I don't think your solution will work. I have multiple commandhandlers that I register in my container thanks to that specific Command in the ` : ICommandHandler` part. By only using `ICommand` , I can not (as far as I know) let my container automatically scan and register all my `ICommandHandler` implementations – S. ten Brinke Nov 21 '18 at 16:08
  • @S.tenBrinke, am I right that my suggestion removes the error but doesn't allow you to filter needed handlers? If yes, I think, you can create a new interface derived from `ICommand` and inherit it in `ExampleCommand`. – Miamy Nov 21 '18 at 17:37
  • @Miamy I haven't checked if it would work since I thought it wouldn't work in my use case. Do you mean that I should have `ExampleCommand : IExampleCommand : ICommand` and then have `public class ExampleCommandHandler : ICommandHandler`? You're saying that having this COULD work with my use case? I'll check it out. It's a lot of interfaces added just to support my tests, I don't think that's a great idea but I'm curious to see if that would work. – S. ten Brinke Nov 21 '18 at 18:50
  • Yes, you got the idea. I think it should work, because your example with my first suggestion was compiled without error. – Miamy Nov 21 '18 at 18:58

0 Answers0