Создание собственного поставщика Ninject для нескольких типов, реализующих один и тот же интерфейс

У меня есть интерфейс, скажем, это IDrawingTool, У меня есть несколько классов, реализующих этот интерфейс, скажем, PencilTool, PenTool, YellowMarkerToolи т. д. Я обычно связываю более одного из этих классов в Ninject, и всегда получаю доступ IDrawingTool случаи по телефону kernel.GetAll<IDrawingTool>, Все идет нормально.

Теперь я хочу создать новый IDrawingTool реализация, ConfigurableBrushToolЭто можно настроить разными способами (скажем, цвет кисти, толщина кисти и т. д.).

Я хотел бы иметь возможность иметь своего рода "фабрику"/"провайдера", которая позволит мне вводить несколько IDrawingToolс (т.е. несколько ConfigurableBrushToolс разными конфигурациями). То есть я хочу иметь возможность сделать что-то вроде следующего:

kernel.Bind<IDrawingTool>.To<PencilTool>();
kernel.Bind<IDrawingTool>.To<PenTool>();
kernel.Bind<IDrawingTool>.ToTypeProvider<ConfigurableBrushToolProvider>();
//...where ConfigurableBrushToolProvider reads e.g. 50 different
//brush configurations (color, thickness, etc) from the database/file/network/whatever
//and binds 50 different ConfigurableBrushTool instances.
//Of course, .ToTypeProvider() doesn't really exist :)

//Later on:
var tools = kernel.GetAll<IDrawingTool>(); //Should return pencil, pen and all 50 brushes

Я не смог найти способ сделать это с Ninject.

Я смотрел на реализацию IProvider / Provider<T>, но он позволяет мне возвращать только один экземпляр того типа, который я предоставляю, нет способа вернуть несколько экземпляров оптом.

Я также посмотрел на IMissingBindingResolverи это очень близко к тому, что мне нужно: если я создаю такой резольвер для IDrawingToolЯ могу вернуть несколько привязок для нескольких ConfigurableBrushTools. Тем не менее, это работает только в том случае, если привязка отсутствует (т. Е. Если нет других IDrawingTool привязок). Как только я добавлю свой PenTool а также PencilTool привязки, привязка для IDrawingTool больше не "отсутствует", и поэтому мой пользовательский распознаватель больше не вызывается.

Есть ли способ реализовать мой сценарий? Т.е. как я могу связать интерфейс с обоими (1) конкретными типами, реализующими интерфейс, и (2) "фабрикой"/"провайдером" многих экземпляров, которые реализуют интерфейс, таким образом, чтобы GetAll вернет все привязки, как (1), так и (2)?

2 ответа

Решение

Прежде всего, похоже, что нет OOTB возможность создания нескольких привязок из одного набора привязок в модуле (по крайней мере, я не нашел ни одной очевидной).
Во-вторых, мне удалось создать PoC с настраиваемым ядром, которое позволяет создавать привязку один ко многим с помощью одного вызова.Bind.To. Это основано на переопределении IKernel.GetBindings(..) метод и поиск всех привязок со специальным параметром. Затем мы можем удалить их, заменив количество созданных пользовательских.
Тем не менее, я думаю, что такая логика будет иметь огромное влияние на производительность, если не будет тщательно оптимизирована (что не сделано для PoC во всяком случае) и должен дойти до производства, только если это действительно нужно. это PoC Вы можете найти здесь.
Что касается меня, то гораздо лучше подходить к рефакторингу существующего кода для внедрения фабричного возвращаемого массива, созданного на лету.

Как насчет связывания пользовательской коллекции (обход многократного внедрения), например:

public interface IToolList : IReadOnlyList<IDrawingTool> {}

и его реализация возвращает как связанные инструменты, так и инструменты, "созданные" из базы данных, что-то вроде:

public class ToolList : List<IDrawingTool>, IToolList
{
    public ToolList(IDrawingTool[] boundTools,... otherDependencies)
    {
       ... create all tools here
    }
}
Другие вопросы по тегам