是否可以设置Ninject绑定来创建同一类的多个实例?

时间:2014-03-31 12:55:43

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

我们有一个(奇怪的?)要求来创建同一个类的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 assemblies = 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辅助角色中创建多个线程,运行相同代码的多个副本将非常有用。

1 个答案:

答案 0 :(得分:3)

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

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<Foo>时,这将创建10个Foo实例。您可以通过在类型上放置一个属性并将其读取为IBindingGenerator来使实例计数可配置。但是,只能在创建绑定时或之前读取配置。


达到同一目标还有其他几种可能性。 我建议只创建一个绑定 - 正如你现在所做的那样。创建一个工厂`IEnumerable CreateMultipleAsConfigured()',根据需要创建任意数量的实例。


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

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

并使用提供程序绑定它:

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

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