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

本文关键字:一类 实例 设置 Ninject 绑定 创建 是否 | 更新日期: 2023-09-27 17:55:13

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

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 约定将实现绑定到一个基础: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 辅助角色中创建多个线程,运行同一代码的多个副本会很有帮助。

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

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

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,并添加项目...