Pull to refresh

Первый взгляд на Unity 2.0

.NET *
Translation
Original author: Dino Esposito
image
Unity – это проект с открытым исходным кодом от группы Patterns & Practices в Microsoft. Цель проекта – предоставить классический IoC фреймворк для разработчиков, позволяющий инстанцировать объекты продвинутым образом и иметь возможность гибкой конфигурации. Unity представляет собой отдельный фреймворк, но часто включается в проекты как часть Enterprise Library. С приходом .NET 4 и Visual Studio 2010, на подходе и новые версии Unity и Enterprise Library. В этой статье рассматривается бета-версия Unity 2.0. Чтобы попробовать фреймворк самим, посетите http://unity.codeplex.com. Релиз Unity 2.0 и Enterprise Library 5.0 намечен на тоже время, что и релизы Visual Studio 2010 и .NET 4, то есть этой весной.

Несколько фактов о Unity 2.0


Когда новый релиз продукта выходит, первый вопрос, который возникает: могу ли я запросто обновить свои старые бинарные компоненты с новыми и быть счастливым? Второй частый вопрос: могу ли я использовать старую версию продукта совместно с новой версией? Для Unity 2.0 ответ на оба вопроса: ДА. Вы легко можете мигрировать имеющиеся приложения на новую версию инструмента и вы так же можете использовать версии 1.2 и 2.0 совместно в контексте одного приложения. Тем не менее, в случае совместного использования вам необходимо проделать несколько действий, чтобы убедиться, например, в том что сборки Unity расположены в разных папках (так как они имеют одно и тоже имя) и каждая ваша сборка зависит только от одной из версий Unity.

Говоря о сборках, нужно заметить, что вся функциональность Unity 2.0 представлена тремя сборками:
  • Microsoft.Practices.Unity
  • Microsoft.Practices.Unity.Configuration
  • Microsoft.Practices.Unity.Interception
Первая содержит ядро библиотеки, остальные две сфокусированы на специфических аспектах, таких как поддержка офлайн-конфигурирования через XML и реализация паттерна Перехват (Interception). Основное отличие с предыдущей версией Unity в отсутствии сборки ObjectBuilder2, код которой отныне включен в ядро Microsoft.Practices.Unity.

В зависимости от того, с какой целью вы использовали Unity 1.2 и какие функции внедряли, вы можете столкнуться, а можете и не столкнуться с трудностями миграции вашего существующего кода на новую версию. На первый взгляд, по моим ощущениям, миграция в большинстве случаев проходит плавно и без проблем, но некоторые изменения все же имеются и кое-какой старый код может оказаться устаревшим в свете новой версии Unity.

Определение зависимостей с Unity 2.0


Так как основная цель Unity – это разрешение зависимостей между классами, первоочередная задача состоит в том, как выразить эти зависимости. Есть два пути: использование офлайн-файла конфигурации и выражение зависимостей через гибкий API во время исполнения.

По умолчанию, Unity считывает конфигурационные параметры из XML-файла, чаще всего это файлы конфигурации приложения вроде app.config или web.config. Но вы не ограничены в своем выборе и можете загружать параметры конфигурации из любого XML-файла, который был включен в ваш проект. Например, у вас есть файл my.config с настройками конфигурации Unity. Следующий код показывает, как вы можете загрузить из него информацию в текущий экземпляр контейнера:

image

Этот код слегка отличается от того, что вы могли использовать в версии 1.2. Старый код отныне помечен как устаревший. Основное отличие в строке кода, которая загружает информацию о конфигурации в контейнер. Теперь у вас есть новый метод Configure у объекта section.

Имейте в виду, что если вы используете конфигурационный файл не по умолчанию, то вам необходимо убедиться в том, что .config-файл размещен в одной папке с исполняемым файлом. Ниже представлен код, который загружает конфигурацию из файла по умолчанию:

image

Конечный код, безусловно, чище, чем код написанный в прошлых версиях. Кроме того, есть еще более приятные новости для Unity-разработчиков: в комплект Unity 2.0 входит очень приятный конфигурационный инструмент, с помощью которого вы можете “выразить и объявить” ваши зависимости.


Рис. 1. Секция Unity, настраиваемая с помощью утилиты конфигурации Enterprise Library

Этот инструмент может сохранять настройки в любой файл, а так же может комбинировать вместе секции из Enterprise Library и Unity. Инструмент так же открывает файлы, которые вы могли создать в Visual Studio либо где-то еще.

Офлайн-конфигурирование – это прекрасная вещь, но она является декларативным API. Есть множество ситуаций, когда вам нужно больше гибкости и, конечно, ситуации в которых вы выбираете подходы, которые предлагают большую гибкость. Альтернативой офлайн-конфигурации на этапе дизайна является конфигурирование во время исполнения.

image

Класс UnityContainer поддерживает гибкий синтаксис, который позволяет вам разбивать на цепочки комбинации методов класса для достижения желаемой конфигурации. Например, вы можете использовать RegisterType для регистрации мэппинга типов и RegisterInstance для регистрации экземпляра определенного типа. Вы так же можете комбинировать вызов с AddExtension чтобы использовать interception API Unity. Кроме того, класс UnityContainer содержит новый метод расширения IsRegistered, который позволяет вам проверить указанный тип на то, был ли он уже зарегистрирован с помощью фреймворка.

image

Этот метод – одна из функций добавленных в Unity 2.0 и полезная в сценариях, когда вы предполагаете интегрировать вместе конфигурации во время дизайна и во время исполнения. Вы можете использовать этот метод для того, чтобы избежать множественных одинаковых регистраций, которые будут автоматически разрешаться с использованием последнего добавленного правила. В Unity 2.0 вы так же обнаружите для себя новую коллекцию Registrations, предназначенную для программной проверки наличия регистраций на момент исполнения. Registrations возвращает коллекцию объектов типа ContainerRegistration, который описан ниже:

image

Как вы можете видеть, объект ContainerRegistration представляет собой точное описание регистрации вне зависимости от того, как она была создана: через XML или программно.

Разрешение зависимостей с помощью Unity 2.0


Unity 2.0 по-прежнему содержит метод Resolve с тем же синтаксисом, который знаком вам по предыдущим версиям. После того, как контейнер был сконфигурирован каким-либо способом, все что нам нужно – это построить экземпляры спроецированных типов. Для этой цели служат методы Resolve и Resolve<T>:
image

Метод разрешения проделывают всю магию по определению структуры целевого типа и поиску его зависимостей, для их разрешения. Как и многие другие IoC-фреймворки, Unity поддерживает зависимости указанные через конструктор и атрибуты внедрения (injection attributes), которые могут быть указаны для свойств или методов. Экземпляр, который возвращает Resolve или Resolve<T> содержит в себе все имеющиеся зависимости разрешенными, в случае, когда зависимость не была разрешена, фреймворк выкидывает исключение.

Unity может также разрешать дженерик-типы, как связанные, так и несвязанные. Ниже представлена регистрация несвязанного дженерик-типа (в котором, тип T неизвестен):

image

Тип ISpecialLogger<T> проецируется на закрытый тип, которому известно только то, как обрабатывать целые значения. Ниже, для примера, описание такого типа:

image

В своем коде вы просите Unity разрешить ISpecialLogger<int> и получить объект, который знает как логировать целые значения:

image

Кольцевые ссылки – это серьезная опасность при использовании Unity и в целом контейнеров IoC. Кольцевые зависимости трудно выявить и они должны рассматриваться как знак плохого дизайна приложения, а не как случайный результат из-за отсутствия функционала в вашем IoC. Когда класс предоставляет несколько конструкторов, Unity по умолчанию использует один с самым большим числом параметров. Порой, это может привести к появлению кольцевых ссылок, который никогда бы не появились, когда вы создаете классы вручную. Например, у нас есть два класса:

image

Все в порядке, пока вы самостоятельно инстанцируете экземпляры класса:

image

Если вы поручите Unity разрешить класс, то получите переполнение стека:

image

Причина исключения с переполнением стека состоит в том, что Unity, используя конструктор с самым большим числом параметров попадает в кольцевые ссылки, когда пытается получить экземпляр MyService чтобы разрешить MyContainer, который в свою очередь требуется для разрешения MyService.

В завершении, стоит описать, что Unity 2.0 содержит несколько новых менеджеров жизненного цикла (lifetime managers). В предыдущей версии у нас было три предопределенных менеджера, плюс возможность создавать свои. В таблице 1 описаны менеджеры доступные в Unity 2.0.

Таблица 1. Менеджеры жизненного цикла в Unity 2.0
Менеджер
Описание
ContainerControlledLifetimeManager
Реализует поведение singleton для объектов. Объект разрушается (disposed), когда разрушается контейнер.
ExternallyControlledLifetimeManager
Реализует поведение singleton, но контейнер не хранит ссылку на объект, так что объект разрушается после выхода из области видимости.
HierarchicalifetimeManager
Новое в Unity 2.0, реализует поведение singleton для объектов. Но, контейнеры-потомки не разделяют экземпляры с родителями.
PerResolveLifetimeManager
Новое в 2.0, реализует поведение похожее на transient lifetime manager, за исключением того, что экземпляры повторно используются в построении графа объектов (instances are reused across build-ups of the object graph).
PerThreadLifetimeManager
Реализует поведение singleton для объектов, но ограничивает их текущим потоком.
TransientLifetimeManager
Возвращает новый экземпляр запрошенного типа при каждом вызове. Это поведение по умолчанию.
Как и ожидалось, разрешение по умолчанию в Unity возвращает новый экземпляр на каждый вызов. То же самое было и в предыдущих версиях.

Заключение


На момент написания этой статьи, фреймворк Unity 2.0 оставался в статусе бета-версии. В этой версии нет ничего революционного. Тем не менее, исправлена конфигурация – область в которой фреймворк уступал другим блокам из Enterprise Library в обоих видах: при дизайне и API. И другое важное изменение: теперь, если вы хотите использовать только чистое внедрение кода, вам нужна всего одна DLL.

Финальный релиз ожидается в апреле, сразу же за релизом Visual Studio 2010 и .NET Framework 4. Тем не менее, Unity 2.0 не специфична для .NET 4 и может быть использована так же и дла .NET 3.5.

Progg it
Tags: .netunityenterprise libraryIoC
Hubs: .NET
Total votes 52: ↑34 and ↓18 +16
Comments 17
Comments Comments 17

Popular right now