Вложенная общая привязка подстановочных знаков в ninject

Есть ли чистый способ привязки к вложенному универсальному «шаблону» в Ninject?

Я знаю, что могу запросить любой произвольный IThing<T> со следующей привязкой:

kernel.Bind(typeof(IThing<>)).To(typeof(Thing<>));

Однако то, что я действительно хочу, это любой произвольный IThing<Foo<T>>. Следующее не работает синтаксически:

kernel.Bind(typeof(IThing<Foo<>>)).To(typeof(FooThing<>));

Это работает синтаксически:

kernel.Bind(typeof(IThing<>).MakeGenericType(typeof(Foo<>))).To(typeof(FooThing<>));

Но нинжект не знает, что с этим делать. Может ли Ninject добиться такого?


person Hans    schedule 05.04.2015    source источник
comment
Сможете ли вы определить интерфейс, подобный public interface IFooThing<T> : IThing<Foo<T>>? потому что тогда можно было бы привязываться как обычно kernel.Bind(typeof(IFooThing<>)).To(typeof(FooThing<>));   -  person Daniel J.G.    schedule 06.04.2015
comment
Да, это, безусловно, вариант, но я не очень люблю интерфейс маркера, поскольку он не дает программе никакого реального смысла. Я бы предпочел, чтобы мой код диктовал привязку внедрения зависимостей, а не наоборот.   -  person Hans    schedule 06.04.2015
comment
Если вам интересно, вариант использования состоит в том, что IThing‹T› на самом деле является IParser‹T›. Я хочу иметь компонуемые парсеры XML. Например, у меня есть документ, который преобразуется в Foo‹T› с узлом, который может быть преобразован в любой формат, поэтому иногда T — это Bar, а иногда — Bat.   -  person Hans    schedule 06.04.2015


Ответы (1)


Простой ответ: нет, вы не можете сделать это с Ninject. На самом деле единственная библиотека DI, которая фактически поддерживает такие сложные привязки с использованием частично закрытых универсальных типов, — это Simple Injector. В Simple Injector вы можете сделать это:

container.RegisterOpenGeneric(
    typeof(IThing<>),
    typeof(Thing<>).MakeGenericType(typeof(Foo<>)));

И в вашем примере у вас есть FooThing<T>, который, вероятно, содержит ограничение вложенного типа следующим образом:

public class FooThing<T> : IThing<Foo<T> { }

Опять же, Ninject не поддерживает это. Я считаю, что Autofac имеет некоторую поддержку для этого до определенного уровня, но только Simple Injector может разрешать типы для вас практически с любыми причудливыми и сложными ограничениями универсального типа. В Simple Injector эта регистрация проста:

container.RegisterOpenGeneric(typeof(IThing<>), typeof(FooThing<>));

И Simple Injector узнает для вас, что он должен разрешить FooThing<int>, когда запрашивается IThing<Foo<int>>.

person Steven    schedule 06.04.2015
comment
Информативный пост, спасибо. Я не уверен, что любая из этих регистраций делает то, что я хочу. Позволит ли второй регистрировать больше экземпляров IThing‹Bar›? - person Hans; 06.04.2015
comment
Привет @Ханс. На самом деле, ни одна из приведенных регистраций не делает того, что вы хотите, потому что они являются примерами Simple Injector, а не Ninject :-). По сравнению с другими библиотеками DI Simple Injector проводит четкое разделение между "нормальным" и регистрации и оформления коллекций. Если вам интересно узнать, как работать с Simple Injector, лучше всего задать новый вопрос здесь, в Stackoverflow. - person Steven; 06.04.2015
comment
Правильно я это понимаю. Меня не особо волнует ninject, просто это то, что я использую прямо сейчас. Хорошая вещь в правильном выполнении DI заключается в том, что довольно просто заменить фреймворк. - person Hans; 06.04.2015
comment
@ Ганс, точно! DI — это применение паттернов и принципов; инструменты приходят после этого. - person Steven; 06.04.2015
comment
Но вот небольшой тизер о Simple Injector. Если у вас есть коллекция (открытых) универсальных типов, вы можете зарегистрировать их в Simple Injector следующим образом: container.RegisterAll(typeof(IThing<>), new[] { typeof(Thing<>), typeof(FooThing<>), typeof(NonGenericThing), typeof(etc) }). Вы можете решить их, вызвав container.GetAllInstances<IThing<Something>>() или указав аргумент коллекции в конструкторе (например, IEnumerable<T>). - person Steven; 06.04.2015