Unity工厂注入

5

我有一个类似下面的接口,我将其注入到Unity容器中。

public interface IMyInstanceFactory
{
    IEnumerable<IMyInstance> GetAll();
}

所有的IMyInstance在运行时之前都已知,即它们可以在引导程序中设置,并且可以从Unity中检索。我对IMyInstanceFactory的具体实现如下:

public class MyInstanceFactory:IMyInstanceFactory
{
    IUnityContainer _container;

    public MyInstanceFactory(IUnityContainer container)
    {
        _container = container;
    }
    public IEnumerable<IMyInstance> GetAll()
    {
        return _container.ResolveAll<IMyInstance>();
    }
}

在我的引导程序中,我会做类似以下的操作:

container.RegisterType<IMyInstance,MyInstance1>;
container.RegisterType<IMyInstance,MyInstance2>;
container.RegisterType<IMyInstance,MyInstance3>;
container.RegisterType<IMyInstanceFactory,MyInstanceFactory>;

这样做非常完美。但是,我不想依赖于容器本身或仅为此实现IMyInstanceFactory,有没有一种方法可以在不实现IMyInstanceFactory的情况下设置它?Unity是否提供了这样的功能?
类似这样的东西...
container.RegisterType<IMyInstanceFactory,factory=>factory.GetAll()>().IsResolvedBy(unity.ResolveAll<IMyInstance>);

我知道Castle可以做到这一点,Unity能否做类似的事情?

如果您的工厂只需要进行这些操作,为什么不直接使用Unity容器呢?或者,如果您不想让代码依赖于Unity,可以使用IServiceLocator。 - cadrell0
2
请不要使用ServiceLocator。在现代应用程序架构中,这被认为是反模式。 - Sebastian Weber
2个回答

3

这里有一个适用于Unity的Castle Windsor类型工厂设施的端口。它将生成你的接口的实现并为你执行ResolveAll

你的引导代码应该像这样:

container.RegisterType<IMyInstance,MyInstance1>("1");
container.RegisterType<IMyInstance,MyInstance2>("2");
container.RegisterType<IMyInstance,MyInstance3>("3");
container.RegisterType<IMyInstanceFactory>(new TypedFactory());

调用 GetAll 将被翻译为容器调用 ResolveAll
端口遵循与 Windsor 相同的约定。

好的,但是你如何注册一个实际的工厂呢?比如说,对于一个没有公共构造函数的类(而且你不想注册一个特定的实例),你如何注册一个 Func<T>,以便容器在需要时可以从头开始创建对象。 - BrainSlugs83
1
@BrainSlugs83 您可以使用InjectionFactory来使用常规工厂 `var container = new UnityContainer(); container.RegisterType<IFoo>(new InjectionFactory(c => Foo.Create())); IFoo foo = container.Resolve<IFoo>();public class Foo : IFoo { private Foo() { } public static Foo Create() { return new Foo(); } }` - Sebastian Weber

0

将容器传递给工厂并没有什么问题,如果工厂作为单例公开,则此方法可以很好地运行,因为获取实例不需要再次传递容器。

另一种选择是在工厂中使用服务定位器解析容器,由于定位器是单例的,因此这种方法类似于前者。


如果您实现了一个基于容器的工厂,您应该注意放置该工厂的位置。请参阅有关基于容器的工厂的段落。 - Sebastian Weber
即使工厂是在组合根中创建的,你仍然必须以某种方式从应用程序中访问它。这就是为什么我提到单例模式。我认为除了我提到的两个选项之外,没有其他选择:一个依赖于容器并作为单例模式公开的工厂,或者一个不依赖于容器并直接访问服务定位器的临时工厂。还有一种不太实用的临时工厂,它明确地依赖于容器。 - Wiktor Zychla
@SebastianWeber:如果没有容器怎么解决?从某种意义上说,我有一个任意类Bar中的任意方法Foo,我想解决工厂?我必须使Bar依赖于容器或组合根(如果Bar深入库中并且组合根位于主模块中,则不可能)。 - Wiktor Zychla
你将工厂接口注入到你的实用类中?!如果这个实用类是静态的,你需要将接口作为方法参数,并确保将工厂接口注入到实用类的调用者中。 - Sebastian Weber
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/20753/discussion-between-wiktor-zychla-and-sebastian-weber - Wiktor Zychla
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接