如何使用现有实例选择要在 IoC 容器中创建的类型
这可能只是一个新手问题,但我有以下问题:
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容器使用与注入的构造函数参数实例匹配的处理器类型。
this is probably just a newbie question, but I have the following:
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) { ... }
}
An instance of either FooSettings or BarSettings is provided from an external source i.e.:
object settings = GetSettings();
And now I would like to resolve ProcessorConsumer based on injecting the existing instance of settings e.g.:
container.RegisterAssemblyTypes(...); // Or similar
container.Inject(settings);
var consumer = container.Resolve<IProcessorConsumer>();
That is if an instance of FooSettings is provided then a FooProcessor is created and injected into the ProcessorConsumer which is then the instance resolved.
I haven't been able to figure out how to do this in either StructureMap, Ninject nor Autofac... probably because I am a newbie when it comes to IoC containers. So answers for all of these or other containers so they can be compared would be highly appreciated.
UPDATE: I am looking for a solution which easily allows for new settings and processors to be added. Also there will be a one-to-on mapping from settings type to processor type. But which also allows for other instances/services to be injected in a given processor type, based on its constructor parameters. I.e. some processor might need a IResourceProvider service or similar. Just an example here.
Ideally, I would like something like
container.For<IProcessor>.InjectConstructorParameter(settings)
or similar. Thereby, guiding the IoC container to use the processor type matching the injected constructor parameter instance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您不需要为此进行依赖注入。您想要一个工厂(当然,您可以使用容器来构建)。工厂会知道如何获取 IProcessorSettings 并返回适当的 IProcessor。简而言之,您可以构建一个工厂,该工厂使用实现 IProcessorSettings 的对象的具体类型和容器来解析适当类型的实例。
You don't want dependency injection for this. You want a factory (which, of course, you can build using your container). The factory would know how to take, say, an
IProcessorSettings
and return the appropriateIProcessor
. In short, you can build a factory that uses the concrete type of an object that implementsIProcessorSettings
and the container to resolve an instance of the appropriate type.我认为您正在寻找的是 StructureMap 中的
ForObject()
方法。它可以根据给定的对象实例关闭开放的泛型类型。您需要对设计进行的关键更改是引入泛型类型:所有重要的内容仍然在
IProcessor
上声明,泛型IProcessor
实际上是只是一个标记界面。然后,每个处理器将实现通用接口,以声明它们期望的设置类型:现在,给定设置对象的实例,您可以检索正确的
IProcessor
:现在您可以告诉 StructureMap 使用每当解析
IProcessor
时,都会执行此逻辑:I think what you are looking for is the
ForObject()
method in StructureMap. It can close an open generic type based on a given object instance. The key change you need to make to your design is to introduce the generic type:All of the important stuff is still declared on
IProcessor
, the genericIProcessor<TSettings>
is really just a marker interface. Each of your processors will then implement the generic interface, to declare which settings type they expect:Now, given an instance of a settings object, you can retrieve the correct
IProcessor
:Now you can tell StructureMap to use this logic whenever it resolves an
IProcessor
:StructureMap 容器公开
Model
属性,该属性允许您查询它包含的实例。StructureMap containers expose the
Model
property which allows you to query for the instances it contains.在 Autofac 中给出:
以下工作:
但是,我发现这相当麻烦,并且希望在 IoC 容器中内置更多的东西。
In Autofac given:
the following works:
However, I find this to be rather cumbersome and was hoping for something more built into an IoC container.
现在,我并不是说这是执行此操作的正确方法。但是,如果您使用 Autofac,这可能是另一种选择。这假设您很高兴注册委托在您尝试解析
IProcessorConsumer
时调用GetSettings
。如果您能够做到这一点,您可以在注册中执行您想要的操作,如下所示:注意:此代码可能是错误的,因为我现在无法尝试。
Now, I'm not saying this is the right way to do this. However, it may be another option if you are using Autofac. This assumes that you are happy for the registration delegate to call
GetSettings
at the point you try and resolve theIProcessorConsumer
. If you are able to do that, you can do what you want in the registration, as below:Note: This code may be wrong as I can't try it right now.
这是您可以得到的最接近正确工厂方法的方法。但也存在一些问题。首先,这是代码;然后我们再谈谈。
那么问题出在哪里呢?这是您为工厂方法提供的不同类型的设置。有时是 FooSettings,有时是 BarSettings。稍后,可能是xxxSettings。每个新类型都会强制重新编译。如果您有一个通用的 Settings 类,情况就不会如此。
另一个问题?您的消费者通过工厂和设置并使用它来获得正确的处理器。如果有人将这些传递给消费者,只需让该实体在工厂上调用 GetProcessor 并将生成的 IProcessor 传递给消费者即可。
Here is as close as you can get to a proper factory method. But there are some issues. First, here's the code; then we'll talk.
So what's the issue? It's the different types of settings that you're giving to your factory method. Sometimes it's FooSettings and sometimes it's BarSettings. Later, it might be xxxSettings. Each new type will force a recompilation. If you had a common Settings class, this would not be the case.
The other issue? Your consumer gets passed the factory and the settings and uses that to get the correct processor. If you have someone passing these to your consumer, just have that entity call GetProcessor on the Factory and pass the resulting IProcessor to the consumer.
我认为问题在于您实际上没有以任何结构化方式指定如何从设置实例解析处理器。让设置对象返回处理器怎么样?这似乎是放置此信息的正确位置:
每个实现都必须解析自己的处理器实现:
并且任何需要处理器的代码都从设置对象获取它,您可以从使用者构造函数引用该对象:
I think the issue is that you haven't actually specified in any structured way how to resolve a processor from a settings instance. How about making the settings object return the processor? That seems to be the right place to put this information:
Each implementation must resolve its own processor implementation:
And any code needing a processor gets it from the settings object, which you can reference from the consumer constructor: