Unity的自定义对象工厂扩展

我正在使用Unity IoC容器,我需要拦截对Resolve的任何调用以获取某个基本接口,并运行我自己的自定义代码来构造这些类型。

换句话说,在下面的示例代码中,当我调用container.Resolve() ,如果它没有具体实现类型的实例,则调用MyFactoryFunction来构造一个,否则我希望它返回缓存副本。

标准Unity容器无法构造这些对象( 更新:因为它们是.NET远程处理对象,因此本地计算机上的任何程序集中都不存在具体类),我不想在前面创建它们使用RegisterInstance存储它们。

 interface IFoo : IBase { ... } interface IFoo2 : IBase { ... } ... container.Resolve(); ... IBase MyFactoryFunction(Type t) { ... } 

我假设我可以创建一个Unity扩展来执行此操作,但我想知道是否已经有一个解决方案我可以借用。

为了完整起见,我应该添加另一个在Unity 2下工作的答案,因为我的其他答案不再适用。 由于您需要制定自定义构建器策略,因此需要稍微多一些。 感谢Unity项目中的ctavares,他们在实现这个方面为这个线程提供了很多帮助:

 public class FactoryUnityExtension : UnityContainerExtension { private ICustomFactory factory; private CustomFactoryBuildStrategy strategy; public FactoryUnityExtension(ICustomFactory factory) { this.factory = factory; } protected override void Initialize() { this.strategy = new CustomFactoryBuildStrategy(factory, Context); Context.Strategies.Add(strategy, UnityBuildStage.PreCreation); Context.Policies.Set(new ParentMarkerPolicy(Context.Lifetime), new NamedTypeBuildKey()); } } public class ParentMarkerPolicy : IBuilderPolicy { private ILifetimeContainer lifetime; public ParentMarkerPolicy(ILifetimeContainer lifetime) { this.lifetime = lifetime; } public void AddToLifetime(object o) { lifetime.Add(o); } } public interface ICustomFactory { object Create(Type t); bool CanCreate(Type t); } public class CustomFactoryBuildStrategy : BuilderStrategy { private ExtensionContext baseContext; private ICustomFactory factory; public CustomFactoryBuildStrategy(ICustomFactory factory, ExtensionContext baseContext) { this.factory = factory; this.baseContext = baseContext; } public override void PreBuildUp(IBuilderContext context) { var key = (NamedTypeBuildKey)context.OriginalBuildKey; if (factory.CanCreate(key.Type) && context.Existing == null) { context.Existing = factory.Create(key.Type); var ltm = new ContainerControlledLifetimeManager(); ltm.SetValue(context.Existing); // Find the container to add this to IPolicyList parentPolicies; var parentMarker = context.Policies.Get(new NamedTypeBuildKey(), out parentPolicies); // TODO: add error check - if policy is missing, extension is misconfigured // Add lifetime manager to container parentPolicies.Set(ltm, new NamedTypeBuildKey(key.Type)); // And add to LifetimeContainer so it gets disposed parentMarker.AddToLifetime(ltm); // Short circuit the rest of the chain, object's already created context.BuildComplete = true; } } } 

更新此答案适用于Unity 1.2。 有关适用于Unity 2的解决方案,请参阅我的其他答案。


好的,我自己实现了扩展。 在构建器中,我将对象缓存,因为我希望它是一个单独的容器。 baseContext的原因是我希望它被缓存在顶级容器中,而不是缓存在请求它的任何子容器中。

  public class FactoryMethodUnityExtension : UnityContainerExtension { private Func factory; public FactoryMethodUnityExtension(Func factory) { this.factory = factory; } protected override void Initialize() { var strategy = new CustomFactoryBuildStrategy(factory, this.Context); Context.Strategies.Add(strategy, UnityBuildStage.PreCreation); } } public class CustomFactoryBuildStrategy : BuilderStrategy { private Func factory; private ExtensionContext baseContext; public CustomFactoryBuildStrategy(Func factory, ExtensionContext baseContext) { this.factory = factory; this.baseContext = baseContext; } public override void PreBuildUp(IBuilderContext context) { var key = (NamedTypeBuildKey)context.OriginalBuildKey; if (key.Type.IsInterface && typeof(T).IsAssignableFrom(key.Type)) { object existing = baseContext.Locator.Get(key.Type); if (existing == null) { // create it context.Existing = factory(key.Type); // cache it baseContext.Locator.Add(key.Type, context.Existing); } else { context.Existing = existing; } } } } 

添加扩展非常简单:

 MyFactory factory = new MyFactory(); container = new UnityContainer(); container.AddExtension(new FactoryMethodUnityExtension(factory.Create)); 

Unity(v2)允许您指定工厂。 它允许几个不同的function,包括采用类型建立/名称等。简单示例:

 UnityContainer cont = new UnityContainer(); 

有一个简单的创建测试方法 – 但这可以用你想要的任何工厂扩展。
这将绕过正常的创建过程(为了简洁起见)调用最长的构造函数,所有后来的行为,包括属性设置仍将被执行。

 cont.RegisterType(new InjectionFactory(c => CreateTest())); var svc = cont.Resolve(); 

Unity容器已经充当了一个知道如何构造(并执行dependency injection)任意类型的工厂,因此接受Type t的工厂看起来是多余的。 你能详细说明为什么这是不可能的吗?

如果这真的不可能(更可能是太多的工作),那么也许你可以用容器注册你的工厂?