[英]Ninject Injection of all instances of a generic type with ninject
我希望能够使用ninject将特定泛型类型的所有实例注入到类中。 例如,我有一堆类似于以下格式的自定义提取器:
public interface IExtract<TEntity>
{
TEntity ExtractFrom(MyBulkExportedEntity exportedEntity);
}
我想将这些提取器的所有实例注入一个负责使用ninject多重绑定处理该文件的类。
即
public class ProcessDataExtract
{
/*This isn't valid c# but demonstrates the intent of what i would like to do*/
public ProcessDataExtract(IEnumerable<IExtract<>> allExtractors)
{
}
public void Process(MyBulkExportedEntity exportedEntity)
{
/*loop through all of the extractors and pull relevant data from the object*/
}
}
在过去,我通过一个管理类(IProvideExtractors)直接访问内核但我不喜欢这种方法并且想知道是否有人知道更好的方法来做到这一点。 使用ninject多重绑定,我可以获得所有对使用kernel.GetAll(typeof(IExtract<>))
感兴趣的实例kernel.GetAll(typeof(IExtract<>))
我正在寻找相关的东西:我不想使用Convention扩展分别指定所有绑定。
第一:您需要注入List<IExtract>
并继承IExtract<T> : IExtract
。 这只是因为在C#中您无法指定包含不同泛型的集合的类型。 正如你在问题中提到的那样,它是无效的语法 - 超出这个答案的一个很好的理由。
您可以稍后将IExtract
的元素从列表中拉出并使用反射来获取泛型类型的paramer并将其转换回来。 或者如果你知道你正在寻找什么提取器:
public IExtract<T> GetExtractor<T>() {
return (IExtract<T>)Extractors.Find(e => e is ExtractImpl<T>);
}
现在你可能有一堆类,你想要一些T
绑定到IExtract`。
Bind<IExtract>().To<ExtractImpl<MyEntity>>();
Bind<IExtract>().To<ExtractImpl<YourEntity>>();
哪里
MyEntity : BaseEntity
YourEntity : BaseEntity
您可以将公约指定如下
Kernel.Bind(x => x.FromThisAssembly().SelectAllClasses()
.InheritedFrom<BaseEntity>()
.BindWith(new GenericArgumentBindingGenerator(typeof(IExtract<>))));
GenericArgumentBindingGenerator
的定义为:
public class GenericArgumentBindingGenerator : IBindingGenerator
{
private readonly Type m_Generic;
public GenericArgumentBindingGenerator(Type generic)
{
if (!generic.IsGenericTypeDefinition)
{
throw new ArgumentException("given type must be a generic type definition.", "generic");
}
m_Generic = generic;
}
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type == null)
throw new ArgumentNullException("type");
if (bindingRoot == null)
throw new ArgumentNullException("bindingRoot");
if (type.IsAbstract || type.IsInterface)
{
return Enumerable.Empty<IBindingWhenInNamedWithOrOnSyntax<object>>();
}
var bindings = new List<IBindingWhenInNamedWithOrOnSyntax<object>>();
IBindingWhenInNamedWithOrOnSyntax<object> binding = bindingRoot
.Bind(typeof(IExtract)) // you maybe want to pass typeof(IExtract) to constructor
.To(m_Generic.MakeGenericType(type));
bindings.Add(binding);
return bindings;
}
}
对此的答案似乎是没有办法用ninject做到这一点
选项A.
我很确定你能做到这一点:
public class ProcessDataExtract
{
public ProcessDataExtract<TExtract>(IEnumerable<IExtract<TExtract>> allExtractors)
{
}
...etc...
}
然后在绑定模块的Load
方法中列出您的绑定:
...
Bind<IExtract<TEntity>>().To<SomeConcreteExtract>();
Bind<IExtract<TEntity>>().To<AnotherConcreteExtract>();
Bind<IExtract<TEntity>>().To<YetAnotherConcreteExtract>();
...
NInject会将它们传递给你的构造函数,这些构造函数会对它们的一堆广告进行广告宣传。 我过去就成功了。
选项B.
更改
public interface IExtract<TEntity>
{
TEntity ExtractFrom(MyBulkExportedEntity exportedEntity);
}
至
public interface IExtract
{
TEntity ExtractFrom<TEntity>(MyBulkExportedEntity exportedEntity);
}
这将允许:
public ProcessDataExtract<TExtract>(IEnumerable<IExtract<TExtract>> allExtractors)
{
}
...etc...
成为:
public ProcessDataExtract(IEnumerable<IExtract> allExtractors)
{
}
...etc...
NInject绑定也会被调整:
...
Bind<IExtract>().To<SomeConcreteExtract>();
Bind<IExtract>().To<AnotherConcreteExtract>();
Bind<IExtract>().To<YetAnotherConcreteExtract>();
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.