我使用的是统一的IoC容器,我需要拦截任何调用解决了一定的基础接口,并运行自己的自定义代码来构建这些类型。
换句话说,在下面的示例代码,当我打电话container.Resolve<IFooN>()
中,如果还没有得到具体的实施类型的实例,它调用MyFactoryFunction
构建一个,否则我希望它返回缓存副本。
标准的统一容器无法构造这些对象( 更新:因为他们是.NET远程对象,所以具体的类不会在本地计算机上的任何组件存在),我不希望创建起来前,他们存储与RegisterInstance。
interface IFoo : IBase { ... }
interface IFoo2 : IBase { ... }
...
container.Resolve<IFoo2>();
...
IBase MyFactoryFunction(Type t)
{
...
}
我假设我能创造一个团结的扩展要做到这一点,但我不知道是否已经有一个解决方案在那里我可以借用。
为了完整起见,我要补充的另一个答案是统一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;
}
}
}
更新这个答案是为统一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));
统一(V2)允许您指定一个工厂。 它允许一对夫妇不同的功能,包括采取类型建立/名称等简单的例子:
UnityContainer cont = new UnityContainer();
有一个简单的创建测试方法 - 不过这可以通过任何你想要的工厂进行扩展。
这将绕过正常的创作过程是(为简便起见)调用构造函数最长以后所有行为,包括PROPERT设置仍将执行。
cont.RegisterType<TestClass>(new InjectionFactory(c => CreateTest()));
var svc = cont.Resolve<TestClass>();
统一容器已经作为一个接受类型T出现多余的工厂,它知道如何构建(和执行依赖注入)的任意类型的,所以你的工厂。 你能否详细了解为何这是不可能的?
如果这是真的不可能(更可能只是工作太多了),那么也许你可以用容器而不是你的工厂注册?