#c# #.net #ioc-container
#c# #.net #ioc-контейнер
Вопрос:
Я хочу знать, какова наилучшая практика использования шаблона IoC при работе с .NET
Например, должен ли я создать SqlConnection
/ OracleConnection
или любого другого поставщика через контейнер IoC или с помощью простого ключевого слова new?
Имеет ли какое-либо значение разделение моего класса на конкретные типы поставщиков (в том числе, когда я хочу использовать только один тип поставщика)?
Ответ №1:
Обслуживание кода — это нечто большее, чем просто замена одного поставщика на другого. Для меня внедрение зависимостей — это скорее сохранение кода логически разделенным и, следовательно, более удобным в обслуживании, чем проверка кода на будущее на тот день, когда сменится поставщик.
DI также позволяет вам легче повторно использовать код из одного проекта в другой, поскольку это делает зависимости между различными частями более явными.
Тем не менее, я никогда не использовал контейнер IOC и никогда не видел необходимости в нем, поэтому я не могу комментировать этот аспект вопроса.
Но вам определенно следует максимально удалить неявные зависимости из вашего кода, просто чтобы сохранить код повторно используемым, поддерживаемым и корректным.
Комментарии:
1. Ну, вы меня поймали на слове «DI — это скорее разделение, чем проверка вашего провайдера на будущее». Очень жаль, что у вас нет большего опыта работы с DI, который вы могли бы предложить. Но все равно 1.
Ответ №2:
Вводить SqlConnection
или a IDbConnection
было бы довольно бесполезно, потому что DbConnection — это непрочная абстракция. Вы можете использовать его только для вызова хранимых процедур или запросов простого SELECT * FROM VIEW
типа. Любые более сложные запросы будут отличаться для каждого диалекта SQL.
У вас будет лучшее изменение успеха, если вы скроете само соединение за абстракцией более высокого уровня, такой как IUserRepository
или какой-либо другой. Реализацией этого интерфейса по умолчанию, вероятно, будет a, SqlUserRepository
который будет взаимодействовать с MS SQL Server, или a, OracleUserRepository
который взаимодействует с Oracle.
Еще лучше было бы отойти от низкого уровня ADO.NET DbConnection API и перейдите на O / RM, такой как LINQ to SQL или Entity Framework. Тогда у вас обычно был бы LinqToSqlUserRepository
.
Обратите внимание, что в этом случае я все еще говорю о XXXUserRepository
. Интерфейс по-прежнему не изменился. Другими словами: IUserRepository
это не дырявая абстракция. Вы можете заменить этот интерфейс для модульного тестирования, в то время как это вряд ли возможно при использовании SqlConnection
.
Комментарии:
1. Я знаю о репозиториях и orm 🙂 Я только что написал очень простой пример использования 🙂 В любом случае спасибо
2. 1 за то, что «Внедрение SqlConnection или IDbConnection было бы довольно бесполезным, потому что DbConnection — это непрочная абстракция», очень верно.
3. Ребята, что означает «дырявая абстракция»?
4. @Davita: Ты пробовал гуглить? В Википедии есть (конечно) определение: en.wikipedia.org/wiki/Leaky_abstraction .
Ответ №3:
Это может иметь значение для модульного тестирования, если вы используете IDbConnection и все другие классы вместо конкретных классов.
Помимо IOC и тому подобного, я на самом деле несколько раз использовал DbFactoryProvider (еще немного информации) для создания своих подключений и других объектов, связанных с БД, и считывал поставщика через строку ConnectionString.
Основная проблема с БД заключается в том, что обычно вы не можете использовать с базой данных только ANSI-SQL, поэтому, пока вы не связаны с конкретными классами, ваш sql нельзя переносить. (ограничение ввода-вывода в MySQL или превышение и разделение в Sql Server).
О DI / IOC с другими материалами, не связанными с БД, здорово отделять ваши классы и удалять зависимости, и это помогает при модульном тестировании, скажем, когда у вас есть сервис, с которым вы работаете, это полезно даже тогда, когда вы не участвуете в модульном тестировании, когда вы работаете с сервисом, а другая команда все еще разрабатывает сервис, вы можете создать поддельный сервис, который в основном решает ваши проблемы (не все), чтобы вы могли работать с чем-то, прежде чем станет доступен реальный сервис.
Примеров намного больше, но работа со службами (репозиторий БД / веб / авторизация / что угодно) — это первое, самое простое добавленное значение.
Ответ №4:
IOC существует для того, чтобы, хотя вы хотите использовать провайдер одного типа, в реальности когда-нибудь что-то изменится, и вам может понадобиться дополнительный адаптер, поэтому лучше использовать IoC вместо создания объекта с использованием ключевого слова new. IoC обеспечивает гибкость, позволяющую со временем что-то менять (по мере изменения требований).
Комментарии:
1. Что ж, если я когда-нибудь захочу использовать другой тип, я думаю, MEF больше подходит для этой цели. Поправьте меня, если я ошибаюсь. Разве использование IoC в данном конкретном случае не повышает качество кода за счет ослабления связи кода?
2. Да, это так, вот почему он гибкий… Я не сказал ничего, что противоречило бы вашему утверждению, и я не поддерживаю его открыто, но это не делает то, что я говорю, неправильным…
3. Я должен решительно не согласиться и сказать, что IOC существует для того, чтобы вы могли разбить функциональность на более мелкие части, следуя принципу единой ответственности, и представлять эти части функциональности с помощью их контракта (интерфейса), не создавая большой нагрузки по созданию экземпляров и предоставлению этих более многочисленных мелких компонентов (это та часть, которую обрабатывает IOC).
Ответ №5:
Было бы хорошей практикой использовать IoC даже для .СЕТЕВЫЕ классы. Это позволит привязать ваш код только к интерфейсу или базовому классу, если он доступен. И не только это, но вы можете использовать свою IoC framework для указания аргументов конструктора. Это может быть полезно для строк подключения в SqlConnection.
Я должен также упомянуть, что использование IoC и написание кода только для интерфейса значительно упростит модульное тестирование. Это особенно верно при работе с подключениями к БД.