自定义对象工厂扩展团结(Custom object factory extension for Un

2019-07-04 21:30发布

我使用的是统一的IoC容器,我需要拦截任何调用解决了一定的基础接口,并运行自己的自定义代码来构建这些类型。

换句话说,在下面的示例代码,当我打电话container.Resolve<IFooN>()中,如果还没有得到具体的实施类型的实例,它调用MyFactoryFunction构建一个,否则我希望它返回缓存副本。

标准的统一容器无法构造这些对象( 更新:因为他们是.NET远程对象,所以具体的类不会在本地计算机上的任何组件存在),我不希望创建起来前,他们存储与RegisterInstance。

interface IFoo : IBase { ... }
interface IFoo2 : IBase { ... }

...
container.Resolve<IFoo2>();

...
IBase MyFactoryFunction(Type t)
{
    ...
}

我假设我能创造一个团结的扩展要做到这一点,但我不知道是否已经有一个解决方案在那里我可以借用。

Answer 1:

为了完整起见,我要补充的另一个答案是统一2下工作,因为我的其他答案不再起作用。 因为你需要做一个自定义生成器的政策,是稍微有点复杂。 由于从谁提供了很多的帮助对统一项目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<ParentMarkerPolicy>(new ParentMarkerPolicy(Context.Lifetime), new NamedTypeBuildKey<ParentMarkerPolicy>());
    }
}

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<ParentMarkerPolicy>(new NamedTypeBuildKey<ParentMarkerPolicy>(), out parentPolicies);

            // TODO: add error check - if policy is missing, extension is misconfigured

            // Add lifetime manager to container
            parentPolicies.Set<ILifetimePolicy>(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;
        }
    }
}


Answer 2:

更新这个答案是为统一1.2。 对于使用Unity 2有效的解决方案,看到我的其他答案。


OK,我已经实现了自己的扩展。 在Builder我缓存,因为我希望它是一个单WRT我的容器对象。 原因baseContext是,我希望它在顶层容器,而不是从它被要求的任何子容器进行缓存。

 public class FactoryMethodUnityExtension<T> : UnityContainerExtension
 {
     private Func<Type,T> factory; 

     public FactoryMethodUnityExtension(Func<Type,T> factory)
     {
         this.factory = factory;
     }

     protected override void Initialize()
     {
         var strategy = new CustomFactoryBuildStrategy<T>(factory, this.Context);
         Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);             
     }
 } 

 public class CustomFactoryBuildStrategy<T> : BuilderStrategy
 {
     private Func<Type,T> factory;
     private ExtensionContext baseContext;

     public CustomFactoryBuildStrategy(Func<Type,T> 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<IBase>(factory.Create));


Answer 3:

统一(V2)允许您指定一个工厂。 它允许一对夫妇不同的功能,包括采取类型建立/名称等简单的例子:

UnityContainer cont = new UnityContainer();

有一个简单的创建测试方法 - 不过这可以通过任何你想要的工厂进行扩展。
这将绕过正常的创作过程是(为简便起见)调用构造函数最长以后所有行为,包括PROPERT设置仍将执行。

cont.RegisterType<TestClass>(new InjectionFactory(c => CreateTest()));

var svc = cont.Resolve<TestClass>();


Answer 4:

统一容器已经作为一个接受类型T出现多余的工厂,它知道如何构建(和执行依赖注入)的任意类型的,所以你的工厂。 你能否详细了解为何这是不可能的?

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



文章来源: Custom object factory extension for Unity