英文:
How to dynamically choose what concrete class to use in dependency injection
问题
I usually write something like this for my DI:
var serviceProvider = new ServiceCollection()
    .AddSingleton<ISomething, Something>()
    .AddSingleton<IOutputMaker, XMLOutputMaker>()
    .AddSingleton<IConfiguration>(Program.configuration)
    .BuildServiceProvider();
But now let's say I read from a config file what type of output I should generate. Notice that above I have this line:
.AddSingleton<IOutputMaker, XMLOutputMaker>()
But I want to be more flexible and say for example if config file says XML then that, if config file says XLSX then maybe this:
.AddSingleton<IOutputMaker, ExcelOutputMaker>()
How can I do that to be more flexible?
I don't know how. Maybe I can call that BuildServiceProvider multiple times?
英文:
I usually write something like this for my DI:
var serviceProvider = new ServiceCollection()
            .AddSingleton<ISomething, Something>()
            .AddSingleton<IOutputMaker, XMLOutputMaker>()
            .AddSingleton<IConfiguration>(Program.configuration)
            .BuildServiceProvider();
But now let's say I read from a config file what type of output I should generate. Notice that above I have this line:
.AddSingleton<IOutputMaker, XMLOutputMaker>()
But I want to be more flexible and say for example if config file says XML then that, if config file says XLSX then maybe this:
.AddSingleton<IOutputMaker, ExcelOutputMaker>()
How can I do that to be more flexible?
I don't know how. Maybe I can call that BuildServiceProvider multiple times?
答案1
得分: 2
以下是您要的翻译内容:
您可以注册具体的实现,然后注册一个工厂,从配置中查询某些内容(我使用了 options,但您也可以直接解析 IConfiguration)以确定要返回哪个。
services.AddOptions<SomeOptions>().BindConfiguration("something");
services.AddSingleton<SomethingImplementationOne>();
services.AddSingleton<SomethingImplementationTwo>();
services
    .AddSingleton<ISomething>(sp => {
        var opts = sp.GetRequiredService<IOptions<SomeOptions>>();
        switch (opts.DefaultService)
        {
            case "One":
                return sp.GetRequiredService<SomethingImplementationOne>();
            default:
                return sp.GetRequiredService<SomethingImplementationTwo>();
        }
    });
为了完整起见,我的 SomeOptions 类如下所示:
public class SomeOptions
{
    public string DefaultService { get; set; }
}
我的配置的 JSON 如下所示:
{
    "something": {
        "defaultService": "One"
    }
}
英文:
You can register the concrete implementations, and then register a factory that consults something from the configuration (I've used options, but you could also just resolve IConfiguration) to determine which one to return.
services.AddOptions<SomeOptions>().BindConfiguration("something");
services.AddSingleton<SomethingImplementationOne>();
services.AddSingleton<SomethingImplementationTwo>();
services
    .AddSingleton<ISomething>(sp => {
        var opts = sp.GetRequiredService<IOptions<SomeOptions>>();
        switch (opts.DefaultService)
        {
            case "One":
                return sp.GetRequiredService<SomethingImplementationOne>();
            default:
                return sp.GetRequiredService<SomethingImplementationTwo>();
        }
    });
For completeness, my SomeOptions class looks like this:
public class SomeOptions
{
    public string DefaultService { get; set; }
}
And my JSON for my configuration looks like this:
{
    "something": {
        "defaultService": "One"
    }
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论