C# Ninject使用Ninject注入泛型类型的所有实例
我希望能够使用ninject将特定泛型类型的所有实例注入到类中。例如,我有一组自定义提取器,其格式类似于:C# Ninject使用Ninject注入泛型类型的所有实例,c#,ninject,constructor-injection,C#,Ninject,Constructor Injection,我希望能够使用ninject将特定泛型类型的所有实例注入到类中。例如,我有一组自定义提取器,其格式类似于: public interface IExtract<TEntity> { TEntity ExtractFrom(MyBulkExportedEntity exportedEntity); } 公共接口IExtract { 从中提取的张力(MyBulkExportedEntity exportedEntity); } 我想将这些提取器的所有实例注入负责使用ni
public interface IExtract<TEntity>
{
TEntity ExtractFrom(MyBulkExportedEntity exportedEntity);
}
公共接口IExtract
{
从中提取的张力(MyBulkExportedEntity exportedEntity);
}
我想将这些提取器的所有实例注入负责使用ninject多重绑定处理该文件的类中
即
公共类ProcessDataExtract
{
/*这不是有效的c#,但表明了我想做的事情的意图*/
公共ProcessDataExtract(IEnumerable AllExtractor)
{
}
公共作废流程(MyBulkExportedEntity exportedEntity)
{
/*循环遍历所有提取器并从对象中提取相关数据*/
}
}
在过去,我通过一个直接访问内核的管理类(IProvideExtractors)来实现这一点,但我不喜欢这种方法,我想知道是否有人知道更好的方法来实现这一点。使用ninject多重绑定,我就可以获得我感兴趣的使用
kernel.GetAll(typeof(IExtract))的所有实例
我很确定你能做到:
public class ProcessDataExtract
{
public ProcessDataExtract<TExtract>(IEnumerable<IExtract<TExtract>> allExtractors)
{
}
...etc...
}
NInject会将它们交付给您的构造函数,该构造函数会宣传对它们的依赖关系。我过去成功地做到了这一点
选项B
改变
public interface IExtract<TEntity>
{
TEntity ExtractFrom(MyBulkExportedEntity exportedEntity);
}
公共接口IExtract
{
从中提取的张力(MyBulkExportedEntity exportedEntity);
}
到
公共接口IExtract
{
从中提取的张力(MyBulkExportedEntity exportedEntity);
}
这将允许:
public ProcessDataExtract<TExtract>(IEnumerable<IExtract<TExtract>> allExtractors)
{
}
...etc...
publicprocessdataextract(IEnumerable allextractor)
{
}
等
将是:
public ProcessDataExtract(IEnumerable<IExtract> allExtractors)
{
}
...etc...
publicprocessdataextract(IEnumerable allextractor)
{
}
等
NInject绑定也将进行调整:
...
Bind<IExtract>().To<SomeConcreteExtract>();
Bind<IExtract>().To<AnotherConcreteExtract>();
Bind<IExtract>().To<YetAnotherConcreteExtract>();
...
。。。
绑定()到();
绑定()到();
绑定()到();
...
这个问题的答案似乎是,对于ninject,没有一种方法可以做到这一点我一直在寻找相关的东西:我不想使用约定扩展单独指定所有绑定
首先:您需要注入列表
并继承IExtract:IExtract
。
这仅仅是因为,在C#中,不能指定包含不同泛型的集合的类型。正如您在问题中指出的,这是无效的语法-除了这个答案之外,还有一个很好的理由
您可以稍后从列表中拉出IExtract
的元素,并使用反射获取泛型类型参数并将其强制转换回。或者,如果您知道要寻找什么样的提取器:
public IExtract<T> GetExtractor<T>() {
return (IExtract<T>)Extractors.Find(e => e is ExtractImpl<T>);
}
在哪里
您可以按如下方式指定约定
Kernel.Bind(x => x.FromThisAssembly().SelectAllClasses()
.InheritedFrom<BaseEntity>()
.BindWith(new GenericArgumentBindingGenerator(typeof(IExtract<>))));
是的,所以在ninject中有一个注入绑定的所有实例的概念,这就是我想要利用的。您可以使用kernel.GetAll(typeof(IExtract))
直接从ninject和上面的实例执行此操作,它将返回一个IEnumerable
,其中包含我的所有提取器。我的问题不是这个,我的问题是我无法在我的构造函数中指定它,因为上面的代码不是有效的C#我更正了语法。但是,您只能使用一个conreteTExtract
。需要是非泛型基类(抽象或非抽象)。或者您可以将类型参数从IExtract
推送到ExtractFrom
,这将消除ProcessDataExtract
的同质性。我将把我的意思添加到我的答案中。我想你的意思是我可以使用可枚举的所有抽取器,我很确定这是不可能的,因为我不认为类型是(IExtract)。IsAssignableFrom(tyepof(IExtract))
可以让你的反射生活更轻松,对具体的IExtract
类使用命名约定,对TEntity
进行编码,这样您就不必每次添加新的循环了。不过,这似乎有点像是在回避这个问题,当然,在过程
方法之外还有一个更优雅的解决方案,IExtract
是否需要通用?因为如果不是这样,我将创建一个非泛型的IExtract
,而IExtract
将继承自IExtract
。在ProcessDataExtract
构造函数中正确注册后,您将依赖IEnumerable AllExtractor
中的一些解决方法。我非常喜欢这个绑定生成器,它看起来很酷,另外,我认为您是对的,扩展一个非泛型将在绑定方面解决这个问题。要替换的IEnvironmentConfigFile是什么?哦,该死的,我错过了一个-从我的代码中得到的;)我想IEnvironmentConfigFile应该是IExtract。但它应该通过GenericArgumentBindingGenerator的构造函数来实现泛型。您确实需要绑定bind().to()代码>如上所述。
...
Bind<IExtract>().To<SomeConcreteExtract>();
Bind<IExtract>().To<AnotherConcreteExtract>();
Bind<IExtract>().To<YetAnotherConcreteExtract>();
...
public IExtract<T> GetExtractor<T>() {
return (IExtract<T>)Extractors.Find(e => e is ExtractImpl<T>);
}
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<>))));
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;
}
}