簡體   English   中英

Ninject使用ninject注入泛型類型的所有實例

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM