我需要注册许多Type映射,但只需要几个我需要使用不同的依赖注入属性重新注册。
使用Unity这似乎是不可能的,它似乎是RegisterType<TFrom, TTo>()
这是一个单元测试,用于演示第二次调用不会清除先前的依赖关系图
[TestClass]
public class UnityContainerTests
{
[TestMethod]
public void UnityShouldCorrectlyResolveReRegisteredType()
{
var container = new UnityContainer();
container.RegisterType<IB, B>(new ContainerControlledLifetimeManager())
.RegisterType<IA, A>(new ContainerControlledLifetimeManager(), new InjectionProperty("B", new B()))
//now re-register mapping without property override, this should
//mean that A.B is resolved to our previously registered singleton but it doesnt
//comment out the line above and notice the test passes
.RegisterType<IA, A>(new ContainerControlledLifetimeManager());
var a = container.Resolve<IA>();
var b = container.Resolve<IB>();
Assert.AreEqual(a.B, b);
}
}
public class A : IA
{
[Dependency] public IB B { get; set; }
}
public interface IA
{
IB B { get; set; }
}
public class B : IB { }
public interface IB { }
任何人都知道有任何变通方法吗?
更新我提出了一个问题&#39;在Unity Codeplex项目门户网站上,如果您遇到过这个问题,那么我建议您对我的请求进行修改https://unity.codeplex.com/workitem/12777
答案 0 :(得分:2)
问题是,当A
向InjectionProperty
注册时,会在Unity内部创建一个策略来解析B
依赖关系。该策略与类型A
的构建密钥相关联,并且类型为SpecifiedPropertiesSelectorPolicy
(实现IPropertySelectorPolicy
)。此策略存储InjectionProperty值(即new B()
)。
再次重新注册A
时,政策未从政策列表中移除,因此当IA
(最终A
)被解析时,Unity会发现IPropertySelectorPolicy
已关联使用类型A
的构建键,并使用该值注入A
。
一种解决方案是删除IPropertySelectorPolicy
。删除后,当A
被解析时,Unity将创建一个新的策略来解析B
依赖关系,这将返回在容器中注册的现有单例。
有了这个,单元测试应该通过:
[TestMethod]
public void UnityShouldCorrectlyResolveReRegisteredType()
{
var container = new UnityContainer();
container.RegisterType<IB, B>(new ContainerControlledLifetimeManager())
.RegisterType<IA, A>(new ContainerControlledLifetimeManager(),
new InjectionProperty("B", new B()))
container.RegisterType<IA, A>(new ContainerControlledLifetimeManager(),
new ClearPropertySelectorPolicy());
var a = container.Resolve<IA>();
var b = container.Resolve<IB>();
Assert.AreEqual(a.B, b);
}
public class ClearPropertySelectorPolicy : InjectionMember
{
public override void AddPolicies(Type serviceType,
Type implementationType,
string name,
Microsoft.Practices.ObjectBuilder2.IPolicyList policies)
{
policies.Clear<IPropertySelectorPolicy>(
new NamedTypeBuildKey(implementationType, name));
}
}
但是如果没有注入属性(可能是构造函数中的依赖项)会怎么样?在这种情况下,清除IPropertySelectorPolicy将不起作用;我们需要明确另一项政策(但要明确哪项政策?)。我认为以下内容清除了构建密钥的所有策略:
public class ClearAllPolicies : InjectionMember
{
public override void AddPolicies(Type serviceType, Type implementationType, string name, IPolicyList policies)
{
var buildKey = new NamedTypeBuildKey(implementationType, name);
policies.Clear<IBuildKeyMappingPolicy>(buildKey);
policies.Clear<IConstructorSelectorPolicy>(buildKey);
policies.Clear<IBuildPlanCreatorPolicy>(buildKey);
policies.Clear<IBuildPlanPolicy>(buildKey);
policies.Clear<IMethodSelectorPolicy>(buildKey);
policies.Clear<IPropertySelectorPolicy>(buildKey);
policies.Clear<ILifetimeFactoryPolicy>(buildKey);
policies.Clear<ILifetimePolicy>(buildKey);
policies.Clear<IBuilderPolicy>(buildKey);
DependencyResolverTrackerPolicy.RemoveResolvers(policies, buildKey);
}
}
一些警告:
另外,我不会真的推荐这种方法作为通用(非测试)方法。根据场景,可能有其他方法可以工作(例如命名注册,解析器覆盖,工厂等)。如果你“设置并忘记它”,Unity往往会发挥最佳效果。也就是说,在应用程序启动时,将执行所有注册,然后在应用程序对象的持续时间内解析而不修改注册。
答案 1 :(得分:1)
我查看了Unity的源代码,当传递给RegisterType的InjectionMembers数组的长度大于0时,似乎只删除了类型的现有BuildPlan。
if (injectionMembers.Length > 0)
{
this.ClearExistingBuildPlan(to, name);
foreach (InjectionMember injectionMember in injectionMembers)
injectionMember.AddPolicies(from, to, name, (IPolicyList) this.policies);
}
针对您描述的问题,可能的解决方法是使用InjectionFactory作为第二个RegisterType调用的InjectionMember。
.RegisterType<IA, A>(new ContainerControlledLifetimeManager(), new InjectionFactory(c=>c.Resolve<IB>());