这可能只是一个新手问题,但我有以下几点:
public class FooSettings {} public class BarSettings {} public class DohSettings {} // There might be many more settings types... public interface IProcessor { ... } public class FooProcessor : IProcessor { public FooProcessor(FooSettings) { ... } } public class BarProcessor : IProcessor { public BarProcessor(BarSettings) { ... } } public class DohProcessor : IProcessor { public DohProcessor(DohSettings) { ... } } // There might be many more processor types with matching settings... public interface IProcessorConsumer {} public class ProcessorConsumer : IProcessorConsumer { public ProcessorConsumer(IProcessor processor) { ... } }
FooSettings或BarSettings的一个实例是从外部源提供的,即:
object settings = GetSettings();
现在我想基于注入现有的设置实例来解决ProcessorConsumer,例如:
container.RegisterAssemblyTypes(...); // Or similar container.Inject(settings); var consumer = container.Resolve<IProcessorConsumer>();
也就是说,如果提供了FooSettings的实例,则创建FooProcessor并将其注入ProcessorConsumer,然后解析实例.
我无法在StructureMap,Ninject和Autofac中弄清楚如何做到这一点……可能是因为我是IoC容器的新手.因此,所有这些或其他容器的答案,以便他们可以比较将非常感激.
更新:我正在寻找一种可以轻松添加新设置和处理器的解决方案.此外,还有从设置类型到处理器类型的一对一映射.但是,它还允许基于其构造函数参数在给定的处理器类型中注入其他实例/服务.即某些处理器可能需要IResourceProvider服务或类似服务.这里只是一个例子.
理想情况下,我想要像
container.For<IProcessor>.InjectConstructorParameter(settings)
或类似的.因此,指导IoC容器使用与注入的构造函数参数实例匹配的处理器类型.
解决方法
我认为你在寻找的是StructureMap中的ForObject()方法.它可以基于给定的对象实例关闭开放的泛型类型.您需要对设计进行的关键更改是引入泛型类型:
public interface IProcessor { } public interface IProcessor<TSettings> : IProcessor{}
所有重要的东西仍然在IProcessor,通用IProcessor< TSettings>上声明.实际上只是一个标记界面.然后,每个处理器将实现通用接口,以声明它们期望的设置类型:
public class FooProcessor : IProcessor<FooSettings> { public FooProcessor(FooSettings settings) { } } public class BarProcessor : IProcessor<BarSettings> { public BarProcessor(BarSettings settings) { } } public class DohProcessor : IProcessor<DohSettings> { public DohProcessor(DohSettings settings) { } }
现在,给定一个设置对象的实例,您可以检索正确的IProcessor:
IProcessor processor = container.ForObject(settings). GetClosedTypeOf(typeof(IProcessor<>)). As<IProcessor>();
现在,您可以告诉StructureMap在解析IProcessor时使用此逻辑:
var container = new Container(x => { x.Scan(scan => { scan.TheCallingAssembly(); scan.WithDefaultConventions(); scan.ConnectImplementationsToTypesClosing(typeof(IProcessor<>)); }); x.For<IProcessor>().Use(context => { // Get the settings object somehow - I'll assume an ISettingsSource var settings = context.GetInstance<ISettingsSource>().GetSettings(); // Need access to full container,since context interface does not expose ForObject var me = context.GetInstance<IContainer>(); // Get the correct IProcessor based on the settings object return me.ForObject(settings). GetClosedTypeOf(typeof (IProcessor<>)). As<IProcessor>(); }); });