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