如何在依赖注入中动态选择要使用的具体类

huangapple go评论73阅读模式
英文:

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&lt;ISomething, Something&gt;()
            .AddSingleton&lt;IOutputMaker, XMLOutputMaker&gt;()
            .AddSingleton&lt;IConfiguration&gt;(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&lt;IOutputMaker, XMLOutputMaker&gt;()

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&lt;IOutputMaker, ExcelOutputMaker&gt;()

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&lt;SomeOptions&gt;().BindConfiguration(&quot;something&quot;);
services.AddSingleton&lt;SomethingImplementationOne&gt;();
services.AddSingleton&lt;SomethingImplementationTwo&gt;();
services
    .AddSingleton&lt;ISomething&gt;(sp =&gt; {
        var opts = sp.GetRequiredService&lt;IOptions&lt;SomeOptions&gt;&gt;();
        switch (opts.DefaultService)
        {
            case &quot;One&quot;:
                return sp.GetRequiredService&lt;SomethingImplementationOne&gt;();
            default:
                return sp.GetRequiredService&lt;SomethingImplementationTwo&gt;();
        }
    });

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:

{
    &quot;something&quot;: {
        &quot;defaultService&quot;: &quot;One&quot;
    }
}

huangapple
  • 本文由 发表于 2023年5月18日 06:48:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76276664.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定