是否可以设置 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 辅助角色中创建多个线程,运行同一代码的多个副本会很有帮助。
你要求它,所以我要给你这个非常臭,丑陋的代码;-)
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,并添加项目...