从 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
解析时,您会丢失所有可能的上下文信息。已解析的类型成为新的 根类型 。这就是为什么直接注入 Container
是 really 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;
}
}
根据
然后,他们只需在需要时从容器实例中获取所需内容即可。即
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
解析时,您会丢失所有可能的上下文信息。已解析的类型成为新的 根类型 。这就是为什么直接注入 Container
是 really 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;
}
}