简体   繁体   English

DI,为一个接口定义注册多个实例

[英]DI, registering multiple instances for one interface definition

I have an interface INavigationService and a simple container that allows registration with and without key. 我有一个接口INavigationService和一个简单的容器,允许使用和不使用密钥进行注册。

This is useful to me as the framework will inject the registered instances into the constructor of my view models. 这对我很有用,因为框架会将注册的实例注入我的视图模型的构造函数中。

Now I have multiple navigation services (due to frames in my UI). 现在我有多个导航服务(由于我的UI中的帧)。 They all implement the same basic interface ( INavigationService ). 它们都实现了相同的基本接口( INavigationService )。

I want to be able to have the container inject these instances into the correct navigation tree (frame + subsequent views/view models) without me having to pass around parameters (DI registration key). 我希望能够让容器将这些实例注入正确的导航树(框架+后续视图/视图模型),而不必传递参数(DI注册密钥)。

How is this usually done? 这通常是怎么做的?

I can imagine something that is attribute based (thus putting the registration key onto all dependent class definitions). 我可以想象基于属性的东西(因此将注册密钥放在所有依赖类定义上)。 But the container doesn't support this. 但是容器不支持这个。 It also seems to be a hassle. 这似乎也很麻烦。

I could also create an interface exclusively for tagging. 我还可以创建一个专门用于标记的接口。 So INavigationService<T> and register each navigation service with a different type argument. 所以INavigationService<T>并使用不同的类型参数注册每个导航服务。 Eg the type of the first view of a frame. 例如,帧的第一个视图的类型。 This would give me the resolution I need, although I would pass around interfaces that do not have any meaning. 这将给我我需要的解决方案,虽然我会传递没有任何意义的接口。

On the other hand, I get IDE support for finding dependent views (for example by creating types like FileTreeNavigation : INavigationService<FileTreeView> 另一方面,我获得IDE支持查找依赖视图(例如通过创建类似FileTreeNavigation : INavigationService<FileTreeView>类型FileTreeNavigation : INavigationService<FileTreeView>

Is there another pattern? 还有其他模式吗?

I'm not sure how this applies to Caliburn Micro, but since the question is about patterns, I'll describe here the way I managed to solve this problem with StrucureMap : using the Ctor<> method which allows specifying concrete types for constructor parameter resolution. 我不确定这如何适用于Caliburn Micro,但由于问题是关于模式,我将在这里描述我用StrucureMap解决这个问题的方法 :使用Ctor<>方法允许指定构造函数参数的具体类型解析度。

Also, I think using specialized interfaces (your FileTreeNavigation example) is great, but if for some reason you don't find this appropriate, read on. 此外,我认为使用专门的接口(您的FileTreeNavigation示例)很棒,但如果由于某种原因您没有找到合适的接口,请继续阅读。

Let's suppose that we have the INavigationService interface and two different implementations: 假设我们有INavigationService接口和两个不同的实现:

public interface INavigationService { }
public class NavigationServiceA : INavigationService { }
public class NavigationServiceB : INavigationService { }

Next, we have two different Service classes, both depending on the INavigationService interface: 接下来,我们有两个不同的Service类,两者都取决于INavigationService接口:

public class ServiceA
{
    private readonly INavigationService _navigationService;

    public ServiceA(INavigationService navigationService)
    {
        _navigationService = navigationService;
    }
}

public class ServiceB
{
    private readonly INavigationService _navigationService;

    public ServiceB(INavigationService navigationService)
    {
        _navigationService = navigationService;
    }
}

Finally, we have a class that we'll resolve using the IoC container. 最后,我们有一个类,我们将使用IoC容器解决。 The class depends on both ServiceA and ServiceB and is defined as follows: 该类依赖于ServiceAServiceB ,定义如下:

public class SomeClassToResolve
{
    private readonly ServiceA _serviceA;
    private readonly ServiceB _serviceB;

    public SomeClassToResolve(ServiceA serviceA, ServiceB serviceB)
    {
        _serviceA = serviceA;
        _serviceB = serviceB;
    }
}

StructureMap offers the possibility of specifying what type to use in order to resolve a constructor parameter. StructureMap提供了指定要使用哪种类型来解析构造函数参数的可能性。 This is how the registration looks like: 这是注册的样子:

ForConcreteType<ServiceA>().Configure.Ctor<INavigationService>().Is<NavigationServiceA>();
ForConcreteType<ServiceB>().Configure.Ctor<INavigationService>().Is<NavigationServiceB>();

Now, when I call container.GetInstance<SomeClassToResolve>(); 现在,当我调用container.GetInstance<SomeClassToResolve>(); it'll construct an instance of SomeClassToResolve , which has instances of ServiceA and ServiceB correctly constructed (having NavigationServiceA and NavigationServiceB , respectively). 它将构造一个SomeClassToResolve的实例,它具有正确构造的ServiceAServiceB实例(分别具有NavigationServiceANavigationServiceB )。

This is one way to do it, that I found to be more straight forward. 这是一种方法,我发现它更直接。 There's also the possibility of doing Conditional Construction , but I think that can get pretty complex. 还有可能进行条件构造 ,但我认为这可能变得相当复杂。

PS: searching for "caliburn micro constructor" I stumbled upon this approach which seems similar to what I'm doing with StructureMap (only that here it's called InjectionConstructor ). PS:搜索“caliburn微构造函数”我偶然发现了这种方法 ,这与我在StructureMap中所做的类似(只是在这里它被称为InjectionConstructor )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM