注入带参数的单例

时间:2015-04-09 19:47:14

标签: c# ninject inversion-of-control

使用Ninject,我有一个接口,我想绑定到具体实现的单个实例。例如:

public interface IFoo { //... }
public class Foo { //... }

现在通常,我会像这样绑定类似的东西:

kernel.Bind<IFoo>().To<Foo>().InSingletonScope();

但是,我需要为Foo的构造函数添加参数。通常,再次,这不会是一个太大的问题(我认为):

kernel.Bind<IFoo>()
    .To<Foo>()
    .InSingletonScope()
    .WithConstructorArgument("bar", myBar);

现在问题是我在设置所有绑定时无法知道myBar的值。我需要推迟到第一次需要IFoo时(注意,实际上我有几个参数要通过)。所以我需要的是一个单例,它在初次使用时会被初始化,只能在那时获得参数。

最好的方法是什么?我假设有Factory的东西可能是解决方案,但我没有看到正确的方法来做到这一点。我不想每次都创建一个 new Foo

3 个答案:

答案 0 :(得分:1)

正如我上面的评论。真正的问题是,当你需要Foo时,你可能没有构造参数。在这种模式中,您可以根据需要绑定所有接口,并在准备好时调用IInitialiser.Initialise(显示您需要保留引用或使其保持静态)。

如果在正确设置之前调用它,Foo将抛出异常

IFoo保持不变

可以调整IInitialiser实现以轮询数据库或响应事件或任何适合您最近配置的最佳配置

using System;

namespace UnitTestProject3
{
    public interface IFoo
    {
        int GetAllTheFoo();
    }

    public interface IInitialiser
    {
        void Initialise(int x);

        int GetX();

        bool IsReady { get; }
    }

    public class Foo : IFoo
    {
        private bool isInitalised;
        private int x;
        private IInitialiser i;
        public Foo(IInitialiser i)
        {
            this.isInitalised = false;
            this.i = i;
        }

        protected void Init()
        {
            if (this.isInitalised)
            {
                return;
            }
            else if (i.IsReady)
            {
                x = i.GetX();
                this.isInitalised = true;
                return;
            }
            else
            {
                throw new Exception("you have not set x");
            }
        }

        public int GetAllTheFoo()
        {
            Init();
            return x;
        }
    }

}

答案 1 :(得分:1)

您可以使用Factory扩展名。

public interface IFooFactory
{
    IFoo CreateFoo(string bar);
    IFoo CreateFoo();
}

public interface IFoo
{
    string Bar { get; set; }
}

public class Foo : IFoo
{
    public string Bar { get; set; }

    public Foo(string bar)
    {
        Bar = bar;
    }
}

kernel.Bind<IFoo>().To<Foo>().InSingletonScope();
kernel.Bind<IFooFactory>().ToFactory();

IFoo foo1 = fooFactory.CreateFoo("myBar");
IFoo foo2 = fooFactory.CreateFoo("myDifferentBar"); // value is basically ignored here
IFoo foo3 = fooFactory.CreateFoo();

这将始终返回相同的Foo实例。当然,如果你首先调用paremeterless方法,它将导致异常。

答案 2 :(得分:0)

鉴于其他两个答案,我可能完全忽略了问题的重点,但为什么不会像你这样简单的工作:

kernel.Bind<IFoo>().ToMethod(x => CreateFoo()).InSingletonScope();

CreateFoo将负责使用您需要的任何参数集构建单个对象。在调用CreateFoo时,您应该已经知道参数是什么。