使用运行时参数解决 Unity 中的命名注册依赖项 [英] Resolve named registration dependency in Unity with runtime parameter

查看:21
本文介绍了使用运行时参数解决 Unity 中的命名注册依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下问题.我注册我的组件并像这样在 Unity 中初始化它们(示例用于控制台应用程序):

I have a following problem. I register my components and initialize them in Unity like this (example is for a Console application):

public class SharePointBootstrapper : UnityBootstrapper
{
    ...

    public object Initialize(Type type, object parameter) =>
        Container.Resolve(type,
            new DependencyOverride<IClientContext>(Container.Resolve<IClientContext>(parameter.ToString())),
            new DependencyOverride<ITenantRepository>(Container.Resolve<ITenantRepository>(parameter.ToString())));

    public void RegisterComponents()
    {
        Container
            .RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString())
            .RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString())
            .RegisterType<ITenantRepository, DocumentDbTenantRepository>(SharePointClientContext.Online.ToString())
            .RegisterType<ITenantRepository, JsonTenantRepository>(SharePointClientContext.OnPremise.ToString());
    }
}

public enum SharePointClientContext
{
    Online,
    OnPremise
}

class Program
{
    static void Main(string[] args)
    {
        ...

        bootstrap.RegisterComponents();
        var bla = bootstrap.Initialize(typeof(ISharePointManager), SharePointClientContext.Online);
    }
}

因此,我使用 RegisterComponents() 在 MVC、WCF、Console 等中注册了我的组件,并使用 Initialize() 初始化它们.

So, I register my components in MVC, WCF, Console etc. once with RegisterComponents() and initialize them with Initialize().

我的问题是,如果我想在运行时初始化特定的命名注册,例如从用户输入,是否可以按照提供的代码(使用 InjectionFactory 或类似的)以其他方式完成?

My question is, if I want to initialize specific named registration at runtime, from e.g. user input, can it be done otherwise as the code presented (with InjectionFactory or similar)?

这段代码运行良好,但我对它的实现并不满意.我有一种感觉,它可以写在 RegisterComponents() 而不是 Initialize() 中,以便它接受某种类型的参数,但我不知道该怎么做.

This code works fine, but I'm not happy with its implementation. I have a feeling that it could be written in RegisterComponents() instead of Initialize() so that it accepts a parameter of some type, but I don't know how to do it.

或者,也许我的整个概念都错了?如果是这样,你有什么建议?我需要从仅在运行时已知的参数中解析命名注册,而不管技术如何(MVC、WCF、控制台等).

Or, is maybe my whole concept wrong? If so, what would you suggest? I need to resolve named registration from a parameter that is only known at runtime, regardless of the technology (MVC, WCF, Console, ...).

谢谢!

推荐答案

与其做不同的注册,我会做不同的解决.

Instead of doing different registrations, I would do different resolves.

假设您需要注入 IClientContext,但您需要根据运行时参数的不同实现.

Let's say that you need to inject IClientContext, but you want different implementations depending on a runtime parameter.

我写了一个类似的答案在这里.您可以注入 IClientContextFactory,而不是注入 IClientContext,它负责返回正确的 IClientContext.这称为策略模式.

I wrote a similiar answer here. Instead of injecting IClientContext, you could inject IClientContextFactory, which would be responsible for returning the correct IClientContext. It's called Strategy Pattern.

public interface IClientContextFactory
{
    string Context { get; } // Add context to the interface.
}

public class SharePointOnlineClientContext : IClientContextFactory
{
    public string Context 
    {
        get 
        {
            return SharePointClientContext.Online.ToString(); 
        }
    }
}

// Factory for resolving IClientContext.
public class ClientContextFactory : IClientContextFactory
{
    public IEnumerable<IClientContext> _clientContexts;

    public Factory(IClientContext[] clientContexts)
    {
        _clientContexts = clientContexts;
    }

    public IClientContext GetClientContext(string parameter)
    {
        IClientContext clientContext = _clientContexts.FirstOrDefault(x => x.Context == parameter);
        return clientContext;
    }
}

像您一样将它们全部注册.但不是注入 IClientContext,而是注入 IClientContextFactor.

Register them all, just as you did. But instead of injecting IClientContext you inject IClientContextFactor.

还有另一种使用 Func 工厂的解决方案.看看选项 3,在 这个答案.有人可能会争辩说这是服务定位器模式的包装器,但我会留待下次讨论.

There also another solution where you use a Func-factory. Look at option 3, in this answer. One may argue that this is a wrapper for the service locator-pattern, but I'll leave that discussion for another time.

public class ClientContextFactory : IClientContextFactory
{
    private readonly Func<string, IClientContext> _createFunc;

    public Factory(Func<string, IClientContext> createFunc)
    {
        _createFunc = createFunc;
    }

    public IClientContext CreateClientContext(string writesTo)
    {
        return _createFunc(writesTo);
    }
}

并使用命名注册:

container.RegisterType<IClientContext, SharePointOnlineClientContext>(SharePointClientContext.Online.ToString());
container.RegisterType<IClientContext, SharePointOnPremiseClientContext>(SharePointClientContext.OnPremise.ToString());

container.RegisterType<IFactory, Factory>(
    new ContainerControlledLifetimeManager(), // Or any other lifetimemanager.
    new InjectionConstructor(
        new Func<string, IClientContext>(
            context => container.Resolve<IClientContext>(context));

用法:

public class MyService
{
    public MyService(IClientContextFactory clientContextFactory)
    {
        _clientContextFactory = clientContextFactory;
    }

    public void DoStuff();
    {
        var myContext = SharePointClientContext.Online.ToString();
        IClientContextclientContext = _clientContextFactory.CreateClientContext(myContext);
    }
}

这篇关于使用运行时参数解决 Unity 中的命名注册依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆