C# 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

我希望能够使用ninject将特定泛型类型的所有实例注入到类中。例如,我有一组自定义提取器,其格式类似于:

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#我更正了语法。但是,您只能使用一个conrete
TExtract
。需要是非泛型基类(抽象或非抽象)。或者您可以将类型参数从
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;
    }
}