.net 如何在不使用服务定位器模式的情况下使用依赖注入的工厂

.net 如何在不使用服务定位器模式的情况下使用依赖注入的工厂,.net,dependency-injection,ninject,factory-pattern,.net,Dependency Injection,Ninject,Factory Pattern,我有一个GUI应用程序。在其中,我允许用户从容器提供的算法列表中进行选择。每个算法将作为另一个视图中的后台任务启动。我需要支持此视图的多个实例,并支持同一算法的多个实例。该视图也将由容器提供。该算法也是有状态的 因此,我需要创建视图和算法的实例,并在运行时将它们绑定在一起。我没有这些实例的静态绑定点,所以我不能使用普通的注入工具(构造函数或属性注入)。我不想调用new,也不想像使用一个容器一样使用容器 我在Castle.Windsor解决了这个问题,但我不得不处理我应用程序中所有的工厂。工厂设计

我有一个GUI应用程序。在其中,我允许用户从容器提供的算法列表中进行选择。每个算法将作为另一个视图中的后台任务启动。我需要支持此视图的多个实例,并支持同一算法的多个实例。该视图也将由容器提供。该算法也是有状态的

因此,我需要创建视图和算法的实例,并在运行时将它们绑定在一起。我没有这些实例的静态绑定点,所以我不能使用普通的注入工具(构造函数或属性注入)。我不想调用
new
,也不想像使用一个容器一样使用容器

我在Castle.Windsor解决了这个问题,但我不得不处理我应用程序中所有的工厂。工厂设计也有点奇怪,因为我必须在处理完实例后将它们返回工厂

我现在正在考虑使用NInject,因为到目前为止,学习曲线和简介文档要好得多,我想为我的团队推荐一个容器。但是对于这样的场景,我认为我必须编写自己的工厂并直接调用内核来解析新实例(工厂中嵌入的服务定位器),以及在注册代码中添加工厂方法

有没有一种通用的方法来解决这个问题,或者这仅仅是一个依赖注入本身并没有被设计来解决的问题


澄清:

我在评论中说,我想为Ninject提供一个具体的答案,我已经得到了。非常感谢:)在现实生活中,我可能会使用已经提出的务实解决方案

但我把我的问题搞砸了,把我的基础作为一个具体的问题。我希望我的标题中的问题能有一个更纯粹的基本答案

是否有一种纯DI技术允许用户在运行时触发组件的新实例?或者所有这些实现都将容器用作服务定位器,或者要求容器具有特定的“怪癖”(例如内置工厂支持、ala Castle.Windsor或即将发布的Ninject工厂功能),而不是只利用“纯”DI的各个方面


我只从Java世界听说过这个词,我不太明白它的意思——请原谅:)这就是我想要的某种“排斥”?

最好创建这样的工厂界面

public interface IFooFactory
{
    IFoo CreateFoo(int someParameter);
}
对于Ninject 2.3,请参阅,并让Ninject通过添加以下配置来实现它

Bind<IFooFactory>().AsFactory();
Bind().AsFactory();
对于2.2,您自己执行。此实现是容器配置的一部分,而不是实现的一部分

public class FooFactory: IFooFactory
{
    private IKernel kernel;
    public FooFactory(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public ISession CreateFoo(int someParameter)
    {
        return this.kernel.Get<IFoo>(
            new ConstructorArgument("someParameter", someParameter));
    }
}
公共类FooFactory:IFooFactory
{
私有IKernel内核;
公共食品工厂(IKernel内核)
{
this.kernel=内核;
}
公共ISession CreateFoo(int-someParameter)
{
返回this.kernel.Get(
新构造函数参数(“someParameter”,someParameter));
}
}

我总是喜欢给出一般性的答案,而不太关注特殊容器的特性。你说的是:

  • 您需要消费者请求新实例
  • 必须返回实例(可能要重用)
  • 使用工厂可能是最好的方法。第二个需求可以通过返回
    IDisposable
    对象来解决。然后可以编写如下代码:

    using (var algorithm = this.algoFactory.CreateNew(type))
    {
        // use algorithm.
    }
    
    有多种方法可以做到这一点,但您可以让算法接口实现
    IDisposable

    public interface IAlgorithm : IDisposable
    {
    }
    
    您可以返回一个decorator,而不是返回实际算法,该decorator允许将该实例返回到池中:

    public sealed class PooledAlgorithmDecorator : IAlgorithm
    {
        private readonly IAlgorithmPool pool;
        private IAlgorithm real;
    
        public PooledAlgorithmDecorator(IAlgorithm real,
            IAlgorithmPool pool)
        {
            this.real = real;
            this.pool = pool;
        }
    
        public void Dispose()
        {
            if (this.real != null)
            {
                this.Pool.ReturnToPool(this.real);
                this.real = null;
            }
        }
    }
    
    现在,您的工厂可以使用decorator包装真正的算法,并将其返回给消费者:

    public class PooledAlgorithmFactory : IAlgorithmFactory
    {
        private readonly IAlgorithmPool pool;
    
        public PooledAlgorithmFactory(IAlgorithmPool pool)
        {
            this.pool = pool;
        }
    
        public IAlgorithm CreateNew(string type)
        {
            var instance = this.pool.GetInstanceOrCreateNew(type);
    
            return new PooledAlgorithmDecorator(instance, this.pool);
        }
    }
    

    这当然只是一个例子。您的设计可能会有所不同。根据您选择的容器,您可能会获得对工厂、对象池等的支持。我认为首先找到正确的设计是很重要的,下一步是看看您的容器是否能够帮助您解决这个问题。

    我非常感谢其他人的回答。他们会帮我解决这个问题。我很可能会接受雷莫的答案,因为它符合我目前实际面临的问题

    就我的理解而言,我还想就我提出的这个更广泛的答案获得反馈


    我不确定依赖项注入是否通过构造函数、属性或方法注入直接支持我提到的机制。这就是我现在认为的“纯”DI——虽然我愿意被动摇。< /P> 我认为注入依赖性意味着相对静态的对象图。它可以从配置文件加载,也可以按程序生成,但它不能直接适应未知的运行时状态,就像用户反复请求新实例一样

    然而,在考虑了其中的一些替代方案后,我开始认为有一些解决方案支持纯度,也许我描述的纯度没有我想象的那么重要。一些不太“纯粹”的选项仍然以一种非常干净的方式在大多数容器中工作,并且似乎很容易添加对容器的支持,以便在剩下的过程中清理它们

    以下是我到目前为止考虑的解决方案(其中一些已经提到)

    参考定制工厂的容器,然后洗手: 您的组件可以根据需要实现。您可以使用任何您想要的容器(只要它支持瞬态实例)。您只需要接受这样一个事实,即您将向代码中注入工厂,这些工厂将直接从容器中解析。当你可以成为布拉格时,谁需要纯洁
    public class ComponentFactory // Might inherit from an interface...
    {
        private readonly IContainer container;
    
        public ComponentFactory(IContainer container)
        {
            this.container = container;
        }
    
        public IComponent Create(IOtherComponent otherComponent)
        {
            return container.Get<IComponent>(otherComponent);
        }
    }
    
    // Black magic - the container implemented it for us!
    // But the container basically implemented our code from the previous example...
    public interface IComponentFactory
    {
        public IComponent Create(IOtherComponent otherComponent);
    }
    
    public class SomeUI
    {
        private readonly IComponentPool componentPool;
    
        public OtherComponent(IComponentPool componentPool)
        {
            this.componentPool = componentPool;
        }
    
        public void DoSomethingWhenButtonPushed()
        {
            var component = componentPool.Get();
            component.DoSomething();
            componentPool.Release(component);
        }
    }
    
    public class ComponentState
    {
        // Hopefully can be less generic than this...
        public Dictionary<string, object> Data { get; set; }
    }
    
    public interface IComponent
    {
        int DoSomething(ComponentState state);
    }
    
    public SomeUI
    {
        private readonly IComponent component;
    
        public OtherComponent(IComponent component)
        {
            this.component = component;
        }
    
        public void DoSomethingWhenButtonPushed()
        {
            var state = new ComponentState();
            component.DoSomething(state);
        }
    }
    
    public class SubComponentFactory // Might inherit from an interface...
    {
        private readonly IContainer container;
    
        public ComponentFactory(IContainer container)
        {
            this.container = container;
        }
    
        public IComponent Create(IOtherComponent otherComponent)
        {
            // Todo: Figure out any lifecycle issues with this.
            // I assume the child containers get disposed with the parent container...
    
            var childContainer = container.CreateChildContainer();
            childContainer.Configure(new SubComponentConfiguration());
    
            return childContainer.Get<SubComponent>(otherComponent);
        }
    }