注入带参数的单例

Inject a singleton with parameters

使用 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

正如我上面的评论。真正的问题是,当你需要 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;
        }
    }

}

您可以使用 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();

这将始终return Foo 的同一个实例。当然如果先调用无参方法会抛出异常

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

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

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