Инверсия управления и зависимостей инъекций в .NET Framework

Существует ли какой-либо конкретный пример/экземпляр DI в качестве архитектурного принципа или шаблона проектирования в самой .NET Framework? Влияют ли какие-либо (или многие) типы в рамках /BCL на IoC?

Имена типов и краткая иллюстрация/объяснение, основанные на С#, будут замечательными!

Это объединило бы потребность в встроенном дизайне DI в качестве наилучшей практики... поскольку она почерпнута из базовой структуры.

Повторяю, я не ищу рамки IoC/DI НО для IoC/DI IN.

РЕДАКТИРОВАТЬ: Просто хотел получить больше экземпляров/примеров... следовательно, щедрость!

Ответ 1

В целом, в BCL не так много примеров DI, возможно, потому, что BCL является довольно автономной структурой, а DI больше относится к архитектуре приложений... Однако вот несколько примеров: до сих пор можно было найти.

Инъекция конструктора

В BCL не так много примеров инжекции конструктора. Лучшие кандидаты

  • System.IO.StreamWriter
  • System.IO.StreamReader

Вложение свойств

  • System.ComponentModel.IComponent.Site

Мы также видим изменение в Workflow Foundation WorkflowRuntime.AddService и связанных с ним методах, хотя вы можете утверждать, что это ближе к методу Injection.

Метод Инъекции

  • System.ComponentModel.Design.IDesigner.Initialize
  • System.ComponentModel.TypeConverter(многие методы принимают ITypeDescriptorContext)
  • System.Web.Mvc.IModelBinder.BindModel(из ASP.NET MVC)

Окружающий контекст

  • System.Threading.Thread.CurrentPrincipal
  • System.Threading.Thread.CurrentCulture
  • System.Threading.Thread.CurrentUICulture
  • System.Diagnostics.Trace.Listeners

FWIW, я привел эти примеры из моей будущей книги.

Ответ 2

Как StreamReader, так и StreamWriter можно рассматривать как примеры IoC/DI.

Каждый из них позволяет вам вводить другой объект Stream (или его производные) для чтения/записи соответственно.

FileInfo fi = new FileInfo(@"C:\MyFile.dat");
StreamWriter sw = new StreamWriter(fi.Open());

Или:

MemoryStream ms = new MemoryStream();
StreamWriter sw = new StreamWriter(ms);

Разрешат ли они:

sw.Write("Hello world!");

То же самое, независимо от того, какой поток вы ввели в вызов конструктору.

Ответ 3

Конечно - IServiceProvider интерфейс был частью Framework с 1.0. Это не DI, как это обычно обсуждается здесь (с использованием "ядра" ), но это IoC с использованием шаблона Locator службы.

Если вы вникнете в какой-либо из кода Windows Forms Designer, вы увидите, что он пронизан либерально такими строками, как этот:

IDesignerOptionService service = 
    (IDesignerOptionService)this.GetService(typeof(IDesignerOptionService));

Если вы работаете с Component, вы получаете доступ к этому через Site. Это довольно распространенные и практически необходимые знания при создании настраиваемых элементов управления.

Это расположение службы, пример учебника. У вас есть общий IServiceProvider, который передает абстрактные сервисы, запрашиваемые по типу службы. Если вы когда-либо захотите создать пользовательские дизайнеры - смарт-теги и т.д. - тогда вам нужно все это знать. Это похоже на ASP.NET.


<суб > P.S. Не используйте IServiceProvider в новом коде. Это очень старый, не общий интерфейс. Если вы создаете библиотеки многократного использования, для работы которых требуется контейнер IoC, вы должны вместо этого использовать общий локатор сервисов. Но даже не используйте это, если вы абсолютно не требуете, чтобы ваша библиотека была агностикой библиотеки DI, используемой на уровне приложения; большинство контейнеров/ядер, специфичных для реализации, предлагают гораздо более богатые API-интерфейсы, которые вы пропустите, если вы прилипнете к CSL.

Ответ 4

Это пример того, как вы можете создать System.ComponentModel.Composition.Hosting.CompositionContainer в .NET 4:

var exeCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var dircatalog = new DirectoryCatalog(".");
var aggregateCatalog = new AggregateCatalog(exeCatalog, dirCatalog);
var exportProvider = new CatalogExportProvider(aggregateCatalog);
var container = new CompositionContainer(exportProvider);

Это пример инъекции зависимостей через аргументы конструктора. Поскольку соблюдался шаблон инъекции зависимостей, эти классы очень расширяемы: вы можете написать свою собственную реализацию ComposablePartCatalog и передать ее конструктору поставщика экспорта. Или вы можете обойти всю концепцию каталогов деталей и написать свою собственную реализацию ExportProvider.

(Кстати, CompostionContainer сам по себе является частью структуры IoC, но это не точка этого примера.)

Ответ 5

.NET, особенно в веб-контексте, предлагает провайдерам определять альтернативные реализации компонентов инфраструктуры. Структура определяет абстрактный базовый класс, определяет одну или две конкретные реализации поверх него и позволяет пользователям при необходимости предоставлять свои собственные реализации.

После определения пользователь не контролирует жизненный цикл своей реализации. Структура принимает и управляет инстанцированием, настройкой и удалением.

Начните с System.Configuration.Provider.ProviderBase.

.NET-классы, реализующие ProviderBase:

  • System.Configuration.ProtectedConfigurationProvider - шифрование и дешифрование данных защищенной конфигурации
    • System.Configuration.DpapiProtectedConfigurationProvider(бетон)
    • System.Configuration.RsaProtectedConfigurationProvider(бетон)
  • System.Configuration.SettingsProvider - пользовательские настройки в архитектуре параметров приложения
    • System.Configuration.LocalFileSettingsProvider(бетон)
    • System.Web.Profile.ProfileProvider
      • System.Web.Profile.SqlProfileProvider(бетон)
  • System.Web.Management.WebEventProvider - настроить обработку событий работоспособности ASP.NET
    • System.Web.Management.BufferedWebEventProvider
      • System.Web.Management.MailWebEventProvider
        • System.Web.Management.SimpleMailWebEventProvider(бетон)
        • System.Web.Management.TemplatedMailWebEventProvider(бетон)
      • System.Web.Management.SqlWebEventProvider(бетон)
    • System.Web.Management.EventLogWebEventProvider(бетон)
    • System.Web.Management.IisTraceWebEventProvider(бетон)
    • System.Web.Management.TraceWebEventProvider(бетон)
    • System.Web.Management.WmiWebEventProvider(бетон)
  • System.Web.Security.MembershipProvider - пользовательское членство в услугах членства
    • System.Web.Security.ActiveDirectoryMembershipProvider(конкретный)
    • System.Web.Security.SqlMembershipProvider(конкретный)
  • System.Web.Security.RoleProvider - настраиваемое управление ролями для служб ролевого управления
    • System.Web.Security.AuthorizationStoreRoleProvider(бетон)
    • System.Web.Security.SqlRoleProvider(бетон)
    • System.Web.Security.WindowsTokenRoleProvider(бетон)
  • System.Web.SessionState.SessionStateStoreProviderBase - хранилища данных состояния сеанса
    • System.Web.SessionState.InProcSessionStateStore(бетон)
    • System.Web.SessionState.OutOfProcSessionStateStore(бетон)
    • System.Web.SessionState.SqlSessionStateStore(бетон)
  • System.Web.SiteMapProvider - пользовательское хранилище данных постоянных данных SiteMap
    • System.Web.StaticSiteMapProvider
      • System.Web.XmlSiteMapProvider(бетон)
  • System.Web.UI.WebControls.WebParts.PersonalizationProvider - загружает и сохраняет данные персонализации от имени экземпляра WebPartPersonalization
    • System.Web.UI.WebControls.WebParts.SqlPersonalizationProvider(конкретный)

Примеры:

Ответ 6

В настоящее время я читаю книгу Искусство модульного тестирования Роя Ошерове. Он упоминает метод, называемый Извлечение и перегрузка (то есть, вводя зависимость в класс путем переопределения виртуального метода, который отвечает за возврат зависимости).

Я думаю, что сталкивался с различными примерами этой техники, например такими:

  • Настройка типа ADO.NET DataTable:
    Если вы выходите из DataTable, у вас есть возможность переопределить различные методы, такие как GetRowType(), CreateInstance() и другие.

  • Настройка дизайнеров действий Workflow Foundation (в .NET 3.5)
    Я не помню точного класса, но я думаю, что если вы хотите создавать собственные проекты, вы получаете новые классы из существующих, а шаблон - один и тот же; вы переопределяете виртуальный метод, который позволяет вам вернуть свою настраиваемую зависимость в фреймворк.