Подумалось тут, что штука достаточно универсальная и вполне имеет смысл перетащить ее в основной реп.
С другой стороны, каждый писатель IoC фреймворка почему то считает необходимым переизобрести велосипед. Особенно удивляет нежелание использовать стандартный фреймворковский IServiceProvider.
У кого какие мысли?
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK>С другой стороны, каждый писатель IoC фреймворка почему то считает необходимым переизобрести велосипед. Особенно удивляет нежелание использовать стандартный фреймворковский IServiceProvider.
AVK>У кого какие мысли?
Ну... тут как. Если говорить про IOC для инфраструктуры, то тут выиграть что-то у MEF/ASP.Net Core DI — шансов ноль. Просто, популярно, в основном работает — чего ещё хотеть-то?
Для биз-сценариев всё в итоге приходит всё к тому же IServiceProvider-у + куче обвязок вокруг него, иначе никак. Вот тут велосипеды вполне могут пригодиться, но их обязательно надо спрятать в отдельный namespace. Иначе вылезут в тех 99% проектов, которым DI особо не нужен
UPD, 2all: с доводами "Service Locator — это антипаттерн" — велкам вот в это обсуждение
Здравствуйте, Sinix, Вы писали:
AVK>>У кого какие мысли? S>Ну... тут как. Если говорить про IOC для инфраструктуры, то тут выиграть что-то у MEF/ASP.Net Core DI — шансов ноль. Просто, популярно, в основном работает — чего ещё хотеть-то?
Не не не, никаких контейнеров. То что сейчас в CodeJam.Extensibility как раз и создавалось как легковесная альтернатива с минимумом навязываемых решений.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Перетащил хелперы к IServiceProvider, интерфейс IServicePublisher (замена кривоватому IServiceContainer), хелперы к нему, и стандартную потокобезопасную реализацию (без локов).
Есть еще простейшая реализация dependency injection в поля. И можно сравнительно быстро соорудить ее же через конструкторы, поверх хелпера CreateInstance, который уже есть. Вопрос — оно нужно?
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>У кого какие мысли?
Такой вопрос: а можно пометить GetService() как [NotNull] + в пару к нему TryGetService()?
Я в курсе, что это отличается от дефолтного поведения IServiceProvider + для этого придётся внести новый интерфейс, но такой вариант на пару порядков удобней.
Говорю это как человек, который регулярно ловит в продакшне забытый кем-то GetRequiredService()
Здравствуйте, Sinix, Вы писали:
AVK>>У кого какие мысли? S>Такой вопрос: а можно пометить GetService() как [NotNull] + в пару к нему TryGetService()?
1) GetService это метод из фреймворка, я его пометить не могу.
2) Есть GetRequiredService, он уже помечен.
S>Я в курсе, что это отличается от дефолтного поведения IServiceProvider + для этого придётся внести новый интерфейс, но такой вариант на пару порядков удобней.
Вот как раз второго IServiceProvider очень не хочется. Вариант опробованный, несущий изрядное количество проблем.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>1) GetService это метод из фреймворка, я его пометить не могу.
Ага. Сам обдумал вопрос — я его криво сформулировал, да ещё и неправильные варианты предложил
Что мне не нравится: самый популярный сценарий у IServiceProvider предполагает, что сервиса может и не быть. Для service provider как для штуки под капотом любого IOC это нормально.
Для публично доступного API это косяк. Потому что в 99% случаев будут использовать вариант по умолчанию, и, соответственно, рано или поздно в поле будет захвачен неполученный сервис, а затем вообще в другом месте всё красиво упадёт с NullRefException. Мой "любимый" баг — по закону подлости похожие тикеты мне скидывают
Предложение такое: каким-либо образом оформить генерик-методы (расширения) так, чтобы вариант по умолчанию падал, если сервиса нет. "Стандартный" GetService() пускай ведёт себя как есть. Тут без нового интерфейса ничего не сделаешь, раз ты говоришь, что с ним проблемы — добавлять не предлагаю
Как генерик-методы обозвать — Get<T>()/TryGet<T>() или GetService<T>()/TryGetService()<T> — это уже не принципиально. Второй вариант получше, но тоже неочевиден, так что предложения приветствуются
Здравствуйте, Sinix, Вы писали:
S>Предложение такое: каким-либо образом оформить генерик-методы (расширения) так, чтобы вариант по умолчанию падал, если сервиса нет.
Осталось понять что такое "вариант по умолчанию".
В CodeJam.Extensibility есть код, который делает инжекцию в поля, помеченные атрибутом. У атрибута есть свойство required. По умолчанию оно true, как ты и хочешь. А тут просто набор хелперов, там нет никаких "по умолчанию".
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Во-первых оно через пакеты для чужих библиотек вроде бы распространяться пока не умеет. А во-вторых даже если я помечу — семантика то стандартных реализаций таки возвращает null, так что толку от аннотаций никакого.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
S>>Предложение такое: каким-либо образом оформить генерик-методы (расширения) так, чтобы вариант по умолчанию падал, если сервиса нет.
AVK>Осталось понять что такое "вариант по умолчанию".
В 99% случаев будет использоваться .GetService<T>(), потому что его автодополнение первым подсунет + оно короче GetRequiredService<T>. Я про него.
На подсказки решарпера надеяться толку нет — у половины целевой аудитории он или не стоит вообще, или не используется.