因此,这将涉及到我展示大量管道的问题,但是我将尝试将其保持在最低限度,以使此问题更简单。我的API端点之一依赖于外部提供程序来完成调用。当用户向该端点发送查询时,他们可以指定在处理查询时希望我们使用的提供程序,我们将这些提供程序称为Bing和Google。因此,我有一个IProvider接口和两个具体的实现BingProvider和GoogleProvider(在我的真实API中,提供程序接口实际上是一个通用接口,但我将通用类排除在外,以避免使此杂物变得不必要。) 。我需要根据查询中的字段来解析正确的提供程序。 Simple Injector不允许注册同一接口的多个具体实现,因此我必须使用工厂。我创建一个看起来像这样的东西:public class ProviderFactory{ private readonly Func<string, IProvider> _Selector; public ProviderFactory(Func<string, IProvider> selector) { this._Selector = selector; } public IProvider Get(string provider) { return this._Selector(provider); }}我通过以下操作向容器注册我的工厂:container.RegisterSingleton<ProviderFactory>(new ProviderFactory(provider => { switch (provider) { case "Bing": return container.GetInstance<BingProvider>() case "Google": return container.GetInstance<GoogleProvider>() default: throw new ArgumentOutOfRangeException("Unknown provider: " + provider); } }));我测试一下。有用。太棒了现在,我需要为我的IProvider创建并注册多个装饰器。 IProvider的每个具体实现都必须在容器解析它们时应用这些装饰器。为了这个例子,可以说我有实现了Decorator1的Decorator2和IProvider。我这样向容器注册它们:container.RegisterDecorator(typeof(IProvider), typeof(Decorator1), Lifestyle.Singleton);container.RegisterDecorator(typeof(IProvider), typeof(Decorator2), Lifestyle.Singleton);这就是问题所在。当我的工厂解析BingProvider或GoogleProvider的实例时,这正是我得到的。我想得到的是Decorator2的一个实例,该实例装饰Decorator1的一个实例,而该实例又装饰了我请求的IProvider的任何具体实现。我认为这是因为我不是专门要求容器解析IProvider的实例,而是要它解析IProvider的具体实现。我似乎已经把自己纠缠在这里了,我不确定最好的解决方法是什么。编辑好吧,在考虑了这一点之后,我明白了为什么装饰器将永远无法解决。以Decorator1和BingProvider为例。 Decorator1和BingProvider都实现IProvider,但是Decorator1不实现BingProvider,所以当我要求Simple Injector解析BingProvider的实例时,甚至不可能给我。我将不得不要求它以某种方式解析Decorator1的实例,但要给我正确的具体实现,并带有适当的装饰器。我理解的很好,但是现在我不确定如何进行。更新资料根据史蒂文的回答,我修改了工厂注册,如下所示:var bingProvider = Lifestyle.Singleton .CreateProducer<IProvider, BingProvider>(container);var googleProvider = Lifestyle.Singleton .CreateProducer<IProvider, GoogleProvider>(container);container.RegisterSingleton<ProviderFactory>(new ProviderFactory(provider => { switch (provider) { case "Bing": return bingProvider.GetInstance(); case "Google": return googleProvider.GetInstance(); default: throw new ArgumentOutOfRangeException("Unknown provider: " + provider); } }));我的新问题是,当我运行单元测试以验证容器时,测试失败并显示如下错误(我必须对此错误消息进行修正以使其与此处的示例相匹配,希望不会导致任何结果。翻译失败): 配置无效。报告了以下诊断警告: -[Torn生活方式] IProvider的注册与IProvider的注册映射到相同的实现和生活方式。它们都映射到Decorator1(Singleton)。这将导致每个注册解析为不同的实例:每个注册将具有自己的实例。 -[Torn生活方式] IProvider的注册与IProvider的注册映射到相同的实现和生活方式。它们都映射到Decorator2(Singleton)。这将导致每个注册解析为不同的实例:每个注册将具有自己的实例。 有关警告的详细信息,请参见Error属性。请参阅https://simpleinjector.org/diagnostics如何解决问题以及如何禁止个别警告。 (adsbygoogle = window.adsbygoogle || []).push({}); 最佳答案 简单注入器不允许注册同一接口的多个具体实现这句话是不正确的。实际上,有多种方法可以做到这一点。我认为最常见的三种方式是:使用条件注册注册类型集合手动创建InstanceProducer实例。特别是选项1和3似乎最适合您的情况,因此让我们从选项3开始:创建InstanceProducers:// Create two providers for IProvider according to the required lifestyle.var bing = Lifestyle.Singleton.CreateProducer<IProvider, BingProvider>(container);var google = Lifestyle.Singleton.CreateProducer<IProvider, GoogleProvider>(container);container.RegisterSingleton<ProviderFactory>(new ProviderFactory(provider => { switch (provider) { case "Bing": return bing.GetInstance(); case "Google": return google.GetInstance(); default: throw new ArgumentOutOfRangeException(); }}));在这里,我们创建两个InstanceProducer实例,每个IProvider实例一个。这里的重要部分是为IProvider抽象创建一个生产器,因为这允许应用IProvider的装饰器。另外,您可以选择将switch-case语句移到ProviderFactory内,并为其提供两个单独的委托;每个提供者一个。例如:public ProviderFactory(Func<IProvider> bingProvider, Func<IProvider> googleProvider) { .. }public IProvider Get(string provider) { switch (provider) { case "Bing": return bingProvider(); case "Google": return googleProvider(); default: throw new ArgumentOutOfRangeException(); }}注册看起来与以前非常相似:var bing = Lifestyle.Singleton.CreateProducer<IProvider, BingProvider>(container);var google = Lifestyle.Singleton.CreateProducer<IProvider, GoogleProvider>(container);container.RegisterSingleton<ProviderFactory>(new ProviderFactory( bingProvider: bing.GetInstance, googleProvider: google.GetInstance));无需将Func<T>委托注入工厂,而是根据您的需要,直接将IProvider注入是可行的。这意味着您的构造函数将如下所示:public ProviderFactory(IProvider bing, IProvider google) { ... }现在,您可以在IProvider上使用条件注册来消除构造函数参数上的歧义:container.RegisterSingleton<ProviderFactory>();container.RegisterConditional<IProvider, BingProvider>( c => c.Consumer.Target.Name == "bing");container.RegisterConditional<IProvider, GoogleProvider>( c => c.Consumer.Target.Name == "google");这样做的好处是您不会延迟构建对象图。解决工厂的消费者问题后,将直接注入所有提供程序。另外,您可能还想尝试一种设计,用分派器抽象代替工厂。对于用户而言,工厂抽象通常不是最简单的解决方案,因为它们现在必须处理工厂类型和返回的服务抽象。另一方面,调度程序或处理器为消费者提供一个单一的抽象。这使得使用者(及其单元测试)通常更简单。这样的调度程序看起来很像IProvider接口本身,但是在其实例方法中添加了string provider参数。例如:interface IProviderDispatcher { void DoSomething(string provider, ProviderData data);}调度程序的实现可能如下所示:public ProviderDispatcher(IProvider bing, IProvider google) { .. }public void DoSomething(string provider, ProviderData data) { this.Get(provider).DoSomething(data);}private IProvider Get(string provider) { switch (provider) { case "Bing": return this.bing; case "Google": return this.google; default: throw new ArgumentOutOfRangeException(); }}调度员的解决方案可以与工厂相同,但是现在我们向消费者隐藏了额外的步骤。如果我们可以完全删除IProviderDispatcher抽象,那就更好了,但这只有在string provider运行时数据是请求期间可用的上下文数据的情况下才有可能。在这种情况下,我们可以执行以下操作:interface IProviderContext { string CurrentProvider { get; }}代替单独的提供程序抽象,我们可以在IProvider上使用代理实现:class ProviderDispatcherProxy : IProvider { public ProviderDispatcherProxy(Func<IProvider> bingProvider, Func<IProvider> googleProvider, IProviderContext providerContext) { ... } void IProvider.DoSomething(ProviderData data) { // Dispatch to the correct provider this.GetCurrentProvider.DoSomething(data); } private IProvider GetCurrentProvider() => switch (this.providerContext.CurrentProvider) { case "Bing": return this.bingProvider(); case "Google": return this.googleProvider(); default: throw new ArgumentOutOfRangeException(); } };}class AspNetProviderContext : IProviderContext { public CurrentProvider => HttpContext.Current.Request.QueryString["provider"];}再次,在内部,它仍然像以前一样,但是现在,由于可以从可用的环境上下文(HttpContext.Current)中解析提供者的价值,因此我们将能够让使用者直接使用IProvider。您可以如下注册:container.RegisterSingleton<IProviderContext>(new AspNetProviderContext());var bing = Lifestyle.Singleton.CreateProducer<IProvider, BingProvider>(container);var google = Lifestyle.Singleton.CreateProducer<IProvider, GoogleProvider>(container);container.RegisterSingleton<IProvider>(new ProviderDispatcherProxy( bingProvider: bing.GetInstance, googleProvider: google.GetInstance));现在,您只需将IProvider注入您的使用者,调度就会在后台自动为您进行。 (adsbygoogle = window.adsbygoogle || []).push({}); 10-06 11:11