Создание собственного поставщика 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
Я могу вернуть несколько привязок для нескольких ConfigurableBrushTool
s. Тем не менее, это работает только в том случае, если привязка отсутствует (т. Е. Если нет других 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
}
}