从 Simple Injector 容器获取条件实例

Get Conditional Instances from Simple Injector container

根据 的讨论,我还有一些遗留代码,它们没有正确地进行 DI,而是在应用程序周围传递了容器,我认为这是因为一些 generic/factory/dynamic 代码意味着当他们这样做时,他们传递容器比重写整个系统更容易!

然后,他们只需在需要时从容器实例中获取所需内容即可。即

public class SomeStageInAPipeline :
{
    private readonly IBlobAccessClient _blobAccessClient;

    public SomeStageInAPipeline (Container container)
    {
        _blobAccessClient = container.GetInstance<IBlobAccessClient>();
    }

这很好,直到我们有条件注册实例的情况,即

container.RegisterConditional(typeof(IBlobAccessClient),
    Lifestyle.Singleton.CreateRegistration(
        () => new BlobAccessClient(srcConnectionString), container),
    c => c.Consumer.Target.Parameter.Name.Contains("src"));

container.RegisterConditional(typeof(IBlobAccessClient),
    Lifestyle.Singleton.CreateRegistration(
        () => new BlobAccessClient(destConnectionString), container),
    c => c.Consumer.Target.Parameter.Name.Contains("dest"));

我可以设置一个作为默认值,即

container.RegisterConditional(typeof(IBlobAccessClient),
    Lifestyle.Singleton.CreateRegistration(
        () => new BlobAccessClient(srcConnectionString), container),
    c => c.Handled == false);

对于 GetInstance(<IBlobAccessClient>) 的现有请求工作正常,但我不知道我将如何访问另一个 "dest" 实例,或者是否有可能。

更新 我希望能够做的是:

public class SomeStageInAPipeline :
{
    private readonly IBlobAccessClient _srcBlobAccessClient;
    private readonly IBlobAccessClient _destBlobAccessClient;

    public SomeStageInAPipeline (Container container)
    {
        _srcBlobAccessClient = container.GetInstance<IBlobAccessClient>();
        // obviously the below just gets me the default instance
        _destBlobAccessClient = container.GetInstance<IBlobAccessClient>();
    }

注册取决于其上下文。但是,当您直接从 Container 解析时,您会丢失所有可能的上下文信息。已解析的类型成为新的 根类型 。这就是为什么直接注入 Containerreally bad idea.

的众多原因之一

您可以改为注入某种 Func<string, IBlobAccessClient> 委托,但由于您已经对 SomeStageInAPipeline 进行了更改,因此直接重构为 构造函数注入 作为如下:

public class SomeStageInAPipeline
{
    private readonly IBlobAccessClient _srcBlobAccessClient;
    private readonly IBlobAccessClient _destBlobAccessClient;

    public SomeStageInAPipeline(
        IBlobAccessClient srcBlobAccessClient,
        IBlobAccessClient destBlobAccessClient)
    {
        _srcBlobAccessClient = srcBlobAccessClient;
        _destBlobAccessClient = destBlobAccessClient;
    }
}

当您从 Container 解析 SomeStageInAPipeline 时,无论是通过调用 GetInstance<SomeStageInAPipeline>() 还是将其注入到消费者中,Simple Injector 都会使用这些条件构建预期的对象图你.

更新:

如果此时无法更改 SomeStageInAPipeline 的构造函数签名,请考虑将 IBlobAccessClient 参数移动到参数对象中,并从 Container 中解析该参数对象:

public sealed class BlobAccessClients
{
    public readonly IBlobAccessClient Src;
    public readonly IBlobAccessClient Dest;

    public BlobAccessClients(IBlobAccessClient src, IBlobAccessClient dest)
    {
        this.Src = src;
        this.Dest = dest;
    }
}

这允许您将 SomeStageInAPipeline 更改为以下内容:

public class SomeStageInAPipeline
{
    private readonly IBlobAccessClient _srcBlobAccessClient;
    private readonly IBlobAccessClient _destBlobAccessClient;

    public SomeStageInAPipeline (Container container)
    {
        var clients = container.GetInstance<BlobAccessClients>();
        _srcBlobAccessClient = clients.Src;
        _destBlobAccessClient = clients.Dest;
    }
}