【问题标题】:Ninject InSingletonScope Creating multiple instancesNinject InSingletonScope 创建多个实例
【发布时间】:2015-11-25 13:04:32
【问题描述】:

我有一个非常简单的测试项目,我尝试告诉 ninject 我的 ILoader 实例应该是单例。无论我做什么,它都会创建它的多个实例。

简单的界面。

public interface ILoader
{
    IEnumerable<int> Get();
}

用于测试目的的实现

public class TestLoader : ILoader
{
    private IEnumerable<int> _Datasource;

    public void Set(IEnumerable<int> enumerable)
    {
        _Datasource = enumerable;
    }
    public IEnumerable<int> Get()
    {
        return _Datasource;
    }
}

依赖它的类

public class TestClass
{
    private ILoader _loader;
    public TestClass(ILoader loader)
    {
        _loader = loader;
    }

    public void Init()
    {
        foreach (var i in _loader.Get())
            Console.WriteLine(i);
    }
}

模块

public class TestModule : NinjectModule
{
    public override void Load()
    {
        Bind<ILoader>().To<TestLoader>();
        Bind<TestLoader>().ToSelf().InSingletonScope();
    }
}

然后运行它。

class Program
{
    static void Main(string[] args)
    {
        var kernel = new StandardKernel(new TestModule());

        var ds = new List<int> { 1, 2 };
        kernel.Get<TestLoader>().Set(ds);

        var tc = kernel.Get<TestClass>();
        tc.Init();
        Console.ReadLine();
    }
}

在这里,我想用 testdata 预加载我的加载器,并且 ninject 应该将相同的加载器注入到我的 TestClass 中。但是,它会创建一个新实例,而这并不是真正需要的行为。

我想有办法解决这个问题。但是,InSingletonScope 的目的是什么?我不应该告诉 ninject 我只想要一个 ILoader 实例吗?

【问题讨论】:

    标签: c# dependency-injection singleton ninject


    【解决方案1】:

    您应该使用构造函数注入(参见this question),而不是使用Set 方法,如下所示:

    public class TestLoader : ILoader
    {
        private IEnumerable<int> _Datasource;
    
        public TestLoader(IEnumerable<int> enumerable)
        {
            _Datasource = enumerable;
        }
        public IEnumerable<int> Get()
        {
            return _Datasource;
        }
    }
    

    然后您将如何注册并解决它:

    static void Main(string[] args)
    {
        var kernel = new StandardKernel();
    
        var ds = new List<int> { 1, 2 };
    
        kernel
            .Bind<ILoader>()
            .To<TestLoader>()
            .InSingletonScope()
            .WithConstructorArgument("enumerable", ds);
    
        var tc1 = kernel.Get<TestClass>();
        var tc2 = kernel.Get<TestClass>();
        tc1.Init();
        tc2.Init();
    
        Console.ReadLine();
    }
    

    在本例中,TestClass 的两个实例将获得相同的 TestLoader 实例注入其中。

    如果由于某种原因您不想使用构造函数注入并且想要保留Set 方法,您可以这样做:

    static void Main(string[] args)
    {
        var kernel = new StandardKernel();
    
        var ds = new List<int> { 1, 2 };
    
        kernel
            .Bind<ILoader>()
            .To<TestLoader>()
            .InSingletonScope();
    
    
        ((TestLoader)kernel.Get<ILoader>()).Set(ds);
    
        var tc1 = kernel.Get<TestClass>();
        var tc2 = kernel.Get<TestClass>();
        tc1.Init();
        tc2.Init();
    
        Console.ReadLine();
    }
    

    【讨论】:

    • 测试并不是真的要加载数据源。它只是用来代表我想在注射之前或之后在课堂上做的一些电话。但似乎如果我在接口上执行 kernel Get 然后强制转换为我的类,它确实返回一个实例。如果我在类而不是接口上获取,为什么它会创建一个新实例?这真的是预期的行为吗?不过,您的最后一个示例是我在这里尝试做的。谢谢
    猜你喜欢
    • 2017-01-30
    • 1970-01-01
    • 2023-04-08
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    • 1970-01-01
    • 2011-05-20
    • 1970-01-01
    相关资源
    最近更新 更多