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

我有 IRespository注册两次(与名称)在以下代码:

// 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) ,我必须像这样手动解决:

public ClientModel(IUnityContainer container)
{
this.dataAccess = container.Resolve<IRepository>(Client);


.....
}

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

就像这样: (注意: 不是真正的代码)

public ClientModel([NamedDependancy("Client")] IRepository dataAccess)
{
this.dataAccess = dataAccess;


.....
}

有办法让我的假代码起作用吗?

40211 次浏览

您应该能够使用參数覆盖

var repository = IOC.Container.Resolve<IRepository>("Client");
var clientModel = IOC.Container.Resolve<ClientModel>(new ParameterOverrides<ClientModel> { {"dataAccess", repository } } );

编辑: 我不知道为什么要传递 UnityContainer ——就我个人而言,我们将我们的依赖项注入到构造函数本身(在我看来这是“正常的”)。但无论如何,您都可以在 RegisterType 和 Resolve 方法中指定名称。

IOC.Container.RegisterType<IRepository, GenericRepository>("Client");
IOC.Container.Resolve<IRepository>("Client");

它会给你注册的那个名字的类型。

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

要告诉容器解析命名的依赖项,需要使用 InjectionParameter对象。对于你的 ClientModel例子,这样做:

container.RegisterType<IClientModel, ClientModel>(
new InjectionConstructor(                        // Explicitly specify a constructor
new ResolvedParameter<IRepository>("Client") // Resolve parameter of type IRepository using name "Client"
)
);

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

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

public ClientModel([Dependency("Client")] IRepository dataAccess)
{
this.dataAccess = dataAccess;


.....
}

这是一个非常晚的回应,但问题仍然出现在谷歌。

不管怎样,五年后。

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

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);
}
}

用法:

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);
}
}

登记:

container.RegisterType<IActionHandler, ActionOne>("One");
container.RegisterType<IActionHandler, ActionTwo>("Two");
container.RegisterType<IStrategyResolver, StrategyResolver>();
container.RegisterType<ISomeInterface, SomeClass>();

现在,好的一面是,在将来添加新策略时,我再也不需要触摸 Strategies yResolver 了。

很简单。非常干净,我保持对统一的依赖,到一个严格的最低限度。唯一一次我会碰到 Strategies yResolver 是在我决定改变容器技术的时候,这是不太可能发生的。

希望这个能帮上忙!

编辑: 我真的不喜欢这个被接受的答案,因为当你在服务的构造函数中使用 Dependency属性时,你实际上很依赖 Unity。Dependency属性是 Unity 库的一部分。在这一点上,您最好在任何地方都传递一个 IUnityContainer依赖项。

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

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

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

编辑(2018-10-20) : 这里有另一种方法,简单地使用一个工厂:

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() {}
}

用法:

public class SomeClass : ISomeClass
{
public SomeClass(ISomeStrategyFactory strategyFactory){


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


}
}

登记:

container.RegisterType<ISomeStrategyFactory, SomeStrategyFactory>();
container.RegisterType<IStrategyA, StrategyA>();
container.RegisterType<IStrategyB, StrategyB>();
container.RegisterType<ISomeClass, SomeClass>();

这第二个建议是同样的事情,但使用工厂设计模式。

希望这个能帮上忙!

不要这样做-只是创建一个 class ClientRepository : GenericRepository { }和利用类型系统。