0

If I have this example interface:

public class BaseReq { }
public class BaseResp { }

public interface IService<in TReq, out TResp>
    where TReq : BaseReq
    where TResp : BaseResp
{
    // Methods
    // ...
}

And I have two "types" of this service that I implement as derived interfaces:

public class TypeAReq : BaseReq { }
public class TypeAResp : BaseResp { }
public interface IServiceTypeA : IService<TypeAReq, TypeAResp> { }

public class TypeBReq : BaseReq { }
public class TypeBResp : BaseResp { }
public interface IServiceTypeB : IService<TypeBReq, TypeBResp> { }

Lastly, if I attempt to assign to a variable that should be assignable to both interfaces:

IServiceTypeA GetTypeAService() { ... }
IServiceTypeB GetTypeBService() { ... }

void Run()
{
    IService<BaseReq, BaseResp> myService = someFlag
        ? GetTypeAService()
        : GetTypeBService();
}

I get an error saying:

Cannot implicitly convert type IService<TypeAReq, TypeAResp> to IService<BaseReq, BaseResp>. An explicit conversion exists (are you missing a cast?)

And if I attempt to cast it, ReSharper warns me by saying:

Suspicious cast: there is no type that inherits from both IService<TypeAReq, TypeAResp> and IService<BaseReq, BaseResp>.

What am I missing or doing wrong? Shouldn't the types be castable because they inherit from the base classes?

qJake
  • 16,821
  • 17
  • 83
  • 135
  • `IService` is contravariant in `TReq` so you need `BaseReq` to be a subtype not a base type of `TypeAReq` for the conversion to be valid. – Lee Oct 05 '17 at 21:45
  • @Lee I'm a bit confused by your comment. What is the different between a subtype and a base type? Or can you explain what change I need to make in order for this to work? – qJake Oct 16 '17 at 17:21
  • 1
    If `A` is a base type of `B` then `B` is a subtype of `A`. In this case `TypeAReq` and `TypeBReq` are both subtypes of `BaseReq`. Your assignment to `myService` is not allowed because it could be unsafe since it would allow you to pass a request type to `myService` it cannot handle e.g. `IService myService = GetTypeAService(); myService.Handle(new TypeBReq());`. There's no static way to make this work so you either need to redesign, cast, or do some runtime checking (e.g. reflection) to handle the invocation. – Lee Oct 16 '17 at 21:11

0 Answers0