C# 向单例注入参数

C# 向单例注入参数,c#,ninject,inversion-of-control,C#,Ninject,Inversion Of Control,使用Ninject,我有一个接口,我想绑定到具体实现的单个实例。例如: public interface IFoo { //... } public class Foo { //... } 现在通常,我会像这样绑定一些东西: kernel.Bind<IFoo>().To<Foo>().InSingletonScope(); 现在的问题是,在设置所有绑定时,我无法知道myBar的值。我需要推迟到第一次需要IFoo(注意,实际上我有几个参数要传递)。所以我需要的是一个单例

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

public interface IFoo { //... }
public class Foo { //... }
现在通常,我会像这样绑定一些东西:

kernel.Bind<IFoo>().To<Foo>().InSingletonScope();
现在的问题是,在设置所有绑定时,我无法知道
myBar
的值。我需要推迟到第一次需要
IFoo
(注意,实际上我有几个参数要传递)。所以我需要的是一个单例,它在第一次使用时是惰性初始化的,并且在那个时候只获取参数


最好的方法是什么?我假设解决方法可能是使用,但我不太明白正确的方法。我不想每次都创建一个新的
Foo

如我上面的评论所示。真正的问题是,当您需要Foo时,您可能没有构造参数。在此模式中,您可以随意绑定所有接口并调用IIInitializer。准备好后进行初始化(OBV需要保留引用或使其保持静态)

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

IFoo保持不变

iInitializer实现可以调整为轮询DB或响应事件,或者任何最适合您的后期配置senario的方式

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;
        }
    }

}

您可以使用工厂扩展

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();
公共接口IFooFactory
{
IFoo CreateFoo(字符串栏);
ifoocreatefoo();
}
公共接口IFoo
{
字符串栏{get;set;}
}
公共类Foo:IFoo
{
公共字符串条{get;set;}
公共Foo(字符串栏)
{
巴=巴;
}
}
kernel.Bind().To().InSingletonScope();
kernel.Bind().ToFactory();
IFoo foo1=foodfactory.CreateFoo(“myBar”);
IFoo foo2=foodfactory.CreateFoo(“myDifferentBar”);//这里基本上忽略了值
IFoo foo3=foodfactory.CreateFoo();

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

给出另外两个答案,我可能完全没有抓住问题的重点,但为什么像这样简单的事情对你不起作用呢:

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

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

您不能在程序中的任何一点绑定吗?@Ewan:不能不传递内核,我不想这样做。除非我遗漏了什么。在我看来,当你谈论DI时,你的问题是“第一次需要IFoo”是不确定的。那么你怎么知道你知道在那一点上的构造参数呢?不,我同意传递内核不是一个好的解决方案。但你有个奇怪的案子我有个更好的。让Foo接受一个IInitializer构造函数。当您调用它的方法时,它会调用initializer来尝试获取所需的参数并初始化它自己。只要这些参数可用,您就可以在初始化器上设置这些参数。这样可以避免在IFoo中添加额外的特定于Foo的内容
kernel.Bind<IFoo>().ToMethod(x => CreateFoo()).InSingletonScope();