Problem
I have the scenario where I want to decide at runtime which service to inject.
public interface IExampleService;
public class ExampleServiceA : IExampleService;
public class ExampleServiceB : IExampleService;
I see different solutions for this right now:
Use injected IServiceProvider
[ServiceProvider]
[Singleton<IExampleService>(Factory = nameof(ChooseExampleService))]
[Singleton<ExampleServiceA>] // No service for type 'releaser.Lib.ExampleServiceA' has been registered.
[Singleton<ExampleServiceB>] // No service for type 'releaser.Lib.ExampleServiceB' has been registered.
public partial class ExampleProvider(bool useA) {
public IExampleService ChooseExampleService(IServiceProvider provider) => useA
? provider.GetRequiredService<ExampleServiceA>()
: provider.GetRequiredService<ExampleServiceB>();
}
⚠️ This works as expected, unless I do not register the example services using the attributes, which will result in runtime errors.
Use pre-generated instances
[ServiceProvider]
[Singleton<IExampleService>(Factory = nameof(ChooseExampleService))]
[Singleton<ExampleServiceA>]
[Singleton<ExampleServiceB>]
public partial class ExampleProvider(bool useA) {
public IExampleService ChooseExampleService(ExampleServiceA a, ExampleServiceB b) => useA ? a : b;
}
⚠️ This also works, with the benefit of being type-safe, but eager evaluated. Missing the service registrations
Proposed solution
Using your IServiceProvider<T> interface or other wrappers to lazily create instances of the service. 1
Edit: maybe using something like Lazy<T> is better suited for this purpose.
[ServiceProvider]
[Singleton<IExampleService>(Factory = nameof(ChooseExampleService))]
[Singleton<ExampleServiceA>]
[Singleton<ExampleServiceB>]
public partial class ExampleProvider(bool useA) {
internal IExampleService ChooseExampleService(IServiceProvider<ExampleServiceA> aProvider, IServiceProvider<ExampleServiceB> bProvider) => useA
? aProvider.GetService()
: bProvider.GetService();
}
✅ This allows Jab to gather the necessary information on service dependencies beforehand (i.e. in this case IExampleService depends on ExampleServiceA and ExampleServiceB during runtime), which is lost when using the plain IServiceProvider interface.
This could be a minimally invasive approach to solve this problem.
Let me know what you think of this idea. If you think this is out of scope, feel free to close this issue, it shall just be my suggestion. I just thought it might be fitting with the whole "build-time checking" and source generation aspects of this project.
Problem
I have the scenario where I want to decide at runtime which service to inject.
I see different solutions for this right now:
Use injected
IServiceProviderUse pre-generated instances
Proposed solution
Using your
IServiceProvider<T>interface or other wrappers to lazily create instances of the service. 1Edit: maybe using something like
Lazy<T>is better suited for this purpose.✅ This allows Jab to gather the necessary information on service dependencies beforehand (i.e. in this case
IExampleServicedepends onExampleServiceAandExampleServiceBduring runtime), which is lost when using the plainIServiceProviderinterface.This could be a minimally invasive approach to solve this problem.
Let me know what you think of this idea. If you think this is out of scope, feel free to close this issue, it shall just be my suggestion. I just thought it might be fitting with the whole "build-time checking" and source generation aspects of this project.
Footnotes
Note that the factory currently has to be internal at most, because of the accessibility level of the
IServiceProvider<T>. ↩