【问题标题】:Is it possible to setup Ninject bindings to create multiple instances of same class?是否可以设置 Ninject 绑定来创建同一类的多个实例?
【发布时间】:2014-03-31 12:55:42
【问题描述】:

我们有一个(奇怪的?)要求来创建同一个类的 X 个实例,并且我们正在使用 Ninject 进行 IoC。显然我们可以通过多次请求相同类型的对象来手动完成:

for (var i = 0; i <= 10; i++)
{
    var obj = _kernel.GetService(typeof(MyType));
    ...
}

这按预期工作,但现在我们必须在我们的代码中访问内核才能做到这一点,那“味道”。我更喜欢在绑定中处理这个,有点像 InRequestScope 的东西。

为了给这一切增加一点复杂性,我们还指定了它自己的对象上的实例数,所以上面的代码实际上更接近于这个: var obj = (MyType)_kernel.GetService(typeof(MyType));

for (var i = 0; i <= obj.NumberOfInstances; i++)
{
    var obj = _kernel.GetService(typeof(MyType));
    ...
}

最后一件事是让它变得一团糟;我们使用 Ninject Conventions 将实现绑定到基础: var 程序集 = AppDomain.CurrentDomain.GetAssemblies();

this.Bind(x => x
      .From(assemblies)
      .SelectAllClasses()
      .InheritedFrom<BaseMyType>()
      .BindAllBaseClasses());

我希望能够使用的实现是这样的:

this.Bind(x => x
      .From(assemblies)
      .SelectAllClasses()
      .InheritedFrom<BaseMyType>()
      .BindAllBaseClasses()
        .Configure(syntax => syntax.InMultipleScope()));

但这可能会也可能不会,或者是个好主意......

有人做过这样的事吗?或者也许您可以看到不同的做法?

关于要求的详细信息:我们在单个 Azure Worker Role 中创建多个线程,运行相同代码的多个副本会很有好处。

【问题讨论】:

    标签: c# azure ninject azure-worker-roles ninject-extensions


    【解决方案1】:

    你要求它,所以我要给你这个非常臭,丑陋的代码;-)

    using System;
    using System.Collections.Generic;
    using FluentAssertions;
    using Ninject;
    using Ninject.Extensions.Conventions;
    using Ninject.Extensions.Conventions.BindingGenerators;
    using Ninject.Syntax;
    using Xunit;
    
    public class MultiBaseBindingGenerator : IBindingGenerator
    {
        public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
        {
            for (int i = 0; i < 10; i++)
            {
                yield return bindingRoot.Bind(type.BaseType).To(type);
            }
        }
    }
    
    public abstract class Foo
    {
    }
    
    public class SomeFoo : Foo
    {
    }
    
    public class SomeFooUser
    {
        public IEnumerable<Foo> Foos { get; set; }
    
        public SomeFooUser(IEnumerable<Foo> foos)
        {
            this.Foos = foos;
        }
    }
    
    public class Demo
    {
        [Fact]
        public void FactMethodName()
        {
            var kernel = new StandardKernel();
    
            kernel.Bind(x => x.FromThisAssembly()
                .SelectAllClasses()
                .InheritedFrom<Foo>()
                .BindWith<MultiBaseBindingGenerator>());
    
            kernel.Get<SomeFooUser>().Foos.Should().HaveCount(10);
        }
    }
    

    这将在您每次注入 IEnumerable&lt;Foo&gt; 时创建 10 个 Foo 实例。您可以通过在类型上放置一个属性并读取它@IBindingGenerator 来使实例计数可配置。但是,只能在创建绑定时或之前读取配置。


    还有其他几种实现相同目标的可能性。 我建议只创建一个绑定 - 正如您现在所做的那样。创建一个工厂 `IEnumerable CreateMultipleAsConfigured()',它会根据需要创建尽可能多的实例。


    另一种可能性是创建自己的集合类型:

    public class MultipleAsConfigured<T> : Collection<T> { }
    

    并使用提供者绑定它:

    IBindingRoot.Bind(typeof(MultipleAsConfigured<>).ToProvider(typeof(MultipleAsConfiguredProvider));   
    

    让提供者读取配置,根据需要实例化尽可能多的对象(使用 IContext.Get()),创建 MultipleAsConfigured,并添加项目...

    【讨论】:

    • 你是对的;它是脏的!但它有效!所以我有点高兴!现在我有一个带有类属性的 POC 来设置计数。只需将其应用于我想要超过 1 个实例的类...谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-26
    • 1970-01-01
    相关资源
    最近更新 更多