I am trying to register a factory that can emit things, and do it so that I can request the most abstract version of this with DI and then decide at registration what combinations of things will actually be used.
The code:
// The thing
public interface IThing
{
void DoSomething();
}
public class ThingA : IThing
{
public void DoSomething() => throw new NotImplementedException();
}
public class ThingB : IThing
{
public void DoSomething() => throw new NotImplementedException();
}
// The factory
public interface IThingFactory<TThing> where TThing : IThing
{
TThing CreateThing();
}
public class MyThingFactory<TThing> : IThingFactory<TThing> where TThing : IThing
{
public TThing CreateThing() => throw new NotImplementedException();
}
If I register and use these as follows, it works:
Services.AddSingleton<IThingFactory<ThingA>, MyThingFactory<ThingA>>();
...
var factory = ServiceProvider.GetRequiredService<IThingFactory<ThingA>>();
// factory is a MyThingFactory<ThingA>
What I really want to do is register things such that I can request a IThingFactory<IThing>
, but for instance, the following definition fails to compile:
Services.AddSingleton<IThingFactory<IThing>, MyThingFactory<ThingA>>();
with
The type 'MyThingFactory' cannot be used as type parameter 'TImplementation' in the generic type or method 'ServiceCollectionServiceExtensions.AddSingleton<TService, TImplementation>(IServiceCollection)'. There is no implicit reference conversion from 'MyThingFactory' to 'IThingFactory'
It's not clear how to register this.
If you enable covariance on the interface using the out
keyword you will be able to register the service.
// +--- Add this
// |
public interface IThingFactory<out TThing> where TThing : IThing
{
TThing CreateThing();
}
Then you can implicitly cast from IThingFactory<ThingA>
to IThingFactory<IThing>
, which will allow registering the type. Like so:
Services.AddSingleton<IThingFactory<IThing>, MyThingFactory<ThingA>>();