0

I can not get around C# covariance for this simple example, here is how I defined my model:

interface IResponse { }
interface ICommand<out TResponse> where TResponse : IResponse { }
class Response : IResponse { }
class Command<TResponse> : ICommand<TResponse> where TResponse : IResponse { }

So I can use it like this

IResponse rsp = new Response(); //Works, obviously!
ICommand<IResponse> cmdi = new Command<Response>(); //Works, but I don't need this 
Command<IResponse> cmd = new Command<Response>(); //Compile time error! :(

The Command in Command<TResponse> doesn't even has any property or method of TResponse type. How can I change it so it works?

MK.Persia
  • 13
  • 2
  • 3
    Classes are always invariant. Only interfaces can be variant. Why don't you need `ICommand cmdi = new Command();`? What exclusive thing do you need from `Command`, that you can't get from `ICommand`? – Sweeper Jun 15 '20 at 08:40
  • I need to persist commands, They are essentially POCO classes, And ```Odata core``` for example breaks if I want to query anything that has a property of type ```List>``` – MK.Persia Jun 15 '20 at 08:50

1 Answers1

1

Your compile time problem occurs, because you declared Command so that it can only receive a TResponse, not an IResponse.

Consider improving your code, instead of

class Command<TResponse>

use

class Command<IResponse>. 

Command will now work with any TResponseXYZ type that implement IResponse, like you intend. To make sure that Command methods can access all relevant properties of TResponseXYZ types, you should publish them as public properties in TResponseXYZ and use the IResponse interface to declare them as get;set; properties. Worked out example:

interface ICommand<out TResponse> where TResponse : IResponse { }

public interface IResponse
{
    int MyField { get; set; }
}

public class TResponseA : IResponse
{
    public int MyField { get; set; }
}

public class TResponseB : IResponse
{
    public int MyField { get; set; }
}

public class Command<TResponse> : ICommand<TResponse> where TResponse : IResponse
{
    public Command(IResponse R)
    {
        // here you can access R.MyField=17 using R.MyField
    }

    public static void Test()
    {
        var rA = new TResponseA() { MyField = 17 };
        var cmdA = new Command<TResponseA>(rA);

        var rB = new TResponseB() { MyField = 17 };
        var cmdB = new Command<TResponseB>(rB);
    }
}
Goodies
  • 1,951
  • 21
  • 26
  • I really appreciate your effort for tying to help me ```1.``` Command doesn't even has any property or method of ```TResponse```: It doesn't need to, ```TResponse``` is used by consumers when passing commands to ```event bus```, ```2.``` ```class Command``` just won't do for reasons I've mentioned in item 1, ```3.``` the last piece of code you sent raises compile time errors too – MK.Persia Jun 15 '20 at 09:31
  • I have changed my code example to include your declarations as is. Either I can'r reproduce your compiling error.. or your question has become unclear to me. Maybe other answers will follow. Success resolving your issue.. – Goodies Jun 15 '20 at 09:51
  • 1
    Buddy! thanks for your dedication to helping me out, I don't think you completely understood my problem, and changing ```Command``` to ```var``` just gets ride of compile time error and won't help the issue of needing ```Command cmd = new Command();``` – MK.Persia Jun 15 '20 at 10:21