首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用Unity,我如何将命名依赖注入到构造函数中?

使用Unity,我如何将命名依赖注入到构造函数中?
EN

Stack Overflow用户
提问于 2011-08-13 05:58:21
回答 4查看 39K关注 0票数 72

我在下面的代码中注册了两次IRespository (带有名称):

代码语言:javascript
复制
// Setup the Client Repository
IOC.Container.RegisterType<ClientEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
    ("Client", new InjectionConstructor(typeof(ClientEntities)));

// Setup the Customer Repository
IOC.Container.RegisterType<CustomerEntities>(new InjectionConstructor());
IOC.Container.RegisterType<IRepository, GenericRepository>
    ("Customer", new InjectionConstructor(typeof(CustomerEntities)));

IOC.Container.RegisterType<IClientModel, ClientModel>();
IOC.Container.RegisterType<ICustomerModel, CustomerModel>();

但是,当我想要解决这个问题(使用IRepository)时,我必须像这样手动解决:

代码语言:javascript
复制
public ClientModel(IUnityContainer container)
{
   this.dataAccess = container.Resolve<IRepository>(Client);

   .....
}

我想要做的是在构造函数中解析它(就像IUnityContainer一样)。我需要一些方法来说明要解析到哪个命名类型。

如下所示:(注意:不是真正的代码)

代码语言:javascript
复制
public ClientModel([NamedDependancy("Client")] IRepository dataAccess)
{
   this.dataAccess = dataAccess;

   .....
}

有没有办法让我的伪代码正常工作?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-08-13 14:19:07

您可以在API、属性中或通过配置文件配置有名称或无名称的依赖项。您在上面没有提到XML,所以我假定您使用的是API。

要告诉容器解析命名依赖项,您需要使用InjectionParameter对象。对于您的ClientModel示例,请执行以下操作:

代码语言:javascript
复制
container.RegisterType<IClientModel, ClientModel>(
    new InjectionConstructor(                        // Explicitly specify a constructor
        new ResolvedParameter<IRepository>("Client") // Resolve parameter of type IRepository using name "Client"
    )
);

这将告诉容器“在解析客户端时,调用接受单个IRepository参数的构造函数。在解析该参数时,除了使用类型之外,还要使用名称‘ClientModel’进行解析。”

如果您想使用属性,您的示例几乎可以工作,您只需更改属性名称:

代码语言:javascript
复制
public ClientModel([Dependency("Client")] IRepository dataAccess)
{
   this.dataAccess = dataAccess;

   .....
}
票数 95
EN

Stack Overflow用户

发布于 2016-06-17 20:58:28

这是一个很晚的回复,但这个问题仍然出现在谷歌上。

所以不管怎样,5年后...

我有一个非常简单的方法。通常,当您需要使用“命名依赖项”时,这是因为您正在尝试实现某种策略模式。在这种情况下,我只是在Unity和我的其余代码之间创建了一个间接级别,称为StrategyResolver,以便不直接依赖Unity。

代码语言:javascript
复制
public class StrategyResolver : IStrategyResolver
{
    private IUnityContainer container;

    public StrategyResolver(IUnityContainer unityContainer)
    {
        this.container = unityContainer;
    }

    public T Resolve<T>(string namedStrategy)
    {
        return this.container.Resolve<T>(namedStrategy);
    }
}

用法:

代码语言:javascript
复制
public class SomeClass: ISomeInterface
{
    private IStrategyResolver strategyResolver;

    public SomeClass(IStrategyResolver stratResolver)
    {
        this.strategyResolver = stratResolver;
    }

    public void Process(SomeDto dto)
    {
        IActionHandler actionHanlder = this.strategyResolver.Resolve<IActionHandler>(dto.SomeProperty);
        actionHanlder.Handle(dto);
    }
}

注册:

代码语言:javascript
复制
container.RegisterType<IActionHandler, ActionOne>("One");
container.RegisterType<IActionHandler, ActionTwo>("Two");
container.RegisterType<IStrategyResolver, StrategyResolver>();
container.RegisterType<ISomeInterface, SomeClass>();

现在,这样做的好处是,在未来添加新策略时,我再也不用接触StrategyResolver了。

这很简单。非常干净,我把对Unity的依赖严格控制在最低限度。只有当我决定改变容器技术时,我才会接触到StrategyResolver,而这是不太可能发生的。

希望这能有所帮助!

编辑:我真的不喜欢被接受的答案,因为当你在服务的构造函数中使用Dependency属性时,你实际上对Unity有一个硬依赖。Dependency属性是Unity库的一部分。在这一点上,您也可以到处传递一个IUnityContainer依赖项。

我更喜欢让我的服务类依赖于我完全拥有的对象,而不是到处依赖外部库。另外,使用Dependency属性使得构造函数签名变得不那么干净和简单。

此外,此技术允许在运行时解析命名依赖项,而不必在构造函数、应用程序配置文件中或使用InjectionParameter中硬编码命名依赖项,这些方法都需要知道在设计时使用什么命名依赖项。

编辑(2016-09-19):对于那些可能想知道的人来说,容器将知道在您将IUnityContainer作为依赖项请求时传递自身,如StrategyResolver构造函数签名中所示。

编辑(2018-10-20):这是另一种方式,简单地使用工厂:

代码语言:javascript
复制
public class SomeStrategyFactory : ISomeStrategyFactory
{
    private IStrategy _stratA;
    private IStrategy _stratB;

    public SomeFactory(IStrategyA stratA, IStrategyB stratB)
    {
        _stratA = stratA;
        _stratB = stratB;
    }

    public IStrategy GetStrategy(string namedStrategy){
        if (namedStrategy == "A") return _stratA;
        if (namedStrategy == "B") return _stratB;
    }
}

public interface IStrategy {
    void Execute();
}

public interface IStrategyA : IStrategy {}

public interface IStrategyB : IStrategy {}

public class StrategyA : IStrategyA {
    public void Execute(){}
}

public class StrategyB : IStrategyB {
    public void Execute() {}
}

用法:

代码语言:javascript
复制
public class SomeClass : ISomeClass
{
    public SomeClass(ISomeStrategyFactory strategyFactory){

        IStrategy strat = strategyFactory.GetStrategy("HelloStrategy");
        strat.Execute();

    }
}

注册:

代码语言:javascript
复制
container.RegisterType<ISomeStrategyFactory, SomeStrategyFactory>();
container.RegisterType<IStrategyA, StrategyA>();
container.RegisterType<IStrategyB, StrategyB>();
container.RegisterType<ISomeClass, SomeClass>();

第二个建议是一样的,但是使用了工厂设计模式。

希望这能有所帮助!

票数 26
EN

Stack Overflow用户

发布于 2011-08-13 06:59:22

您应该能够使用ParameterOverrides

代码语言:javascript
复制
var repository = IOC.Container.Resolve<IRepository>("Client");
var clientModel = IOC.Container.Resolve<ClientModel>(new ParameterOverrides<ClientModel> { {"dataAccess", repository } } );

编辑:我不确定你为什么要传递UnityContainer --就我个人而言,我们将依赖注入到构造函数本身中(从我所见,这是“正常的”)。但不管怎样,您都可以在RegisterType和Resolve方法中指定名称。

代码语言:javascript
复制
IOC.Container.RegisterType<IRepository, GenericRepository>("Client");
IOC.Container.Resolve<IRepository>("Client");

它将为您提供您为该名称注册的类型。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7046779

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档