Basically we have a Interface that takes another interface (constrained) When you create a hard implementation of that interface through a base class, the conversion fails as there is no implicit conversion.
I know that was probably hard to follow so we've gone ahead and made the simplest .NET 6 console app possible to show this issue.
Definition:
public interface IClient { }
public abstract class ClientBase : IClient { }
public class Client : ClientBase, IClient { }
public interface IServer<TClient> where TClient : IClient { }
public abstract class ServerBase<TClient>
: IServer<TClient> where TClient : IClient { }
public class Server : ServerBase<Client> { }
Console:
using Microsoft.Extensions.DependencyInjection;
namespace ConsoleApp;
public class Program
{
public static IServiceCollection Services = new ServiceCollection();
public static ServiceProvider Provider;
public static void Main()
{
Services.AddSingleton<IClient, Client>();
Services.AddSingleton<IServer<IClient>, Server>();
Provider = Services.BuildServiceProvider();
var server = Provider.GetService<IServer<IClient>>();
}
}
Server
can be type casted to an IServer
Client
can be type casted to an IClient
But you cannot implicitly type case a Server
instance to an IServer<IClient>
even though the base implementations all can be casted to those types.
I'm absolutely confused about this. We can fix it by changing DI to take an IServer<Client>
but then one of our services which looks for ALL implementations of IServer<IClient>
cannot work anymore since we are providing a concrete implementation.
CodePudding user response:
The problem is that the base class is not IServer<IClient>
but defined as IServer<Client>
. Which cannot be implicitly converted. This is a common problem when using generics. :-(
This is a covariant problem. It will work when you define it with out
:
public interface IServer<out TClient> where TClient : IClient
{
}
Covariance enables you to use a more derived type than that specified by the generic parameter. This allows for implicit conversion of classes that implement covariant interfaces and implicit conversion of delegate types.