PostSharp Thread\Dispatcher Toolkit

Сложность 100

Сегодня я хочу рассказать о еще одном тулките от PostSharp, который позволяет сократить количество служебного кода на порядок. Впрочем, любое решение с помощью PostSharp сильно облегчает работу программиста, позволяя избавиться от повторяющегося кода, вынеся его в отдельный класс.

Итак, сегодня в программе тулкит, который позволяет с помощью атрибутов указать выполнение метода в отдельном потоке, а так же указать какие методы вызывать в потоке UI. Собственно вот и весь функционал.

О том как решаются эти проблемы в «традиционном» стиле, я рассказывал в статье про эволюцию сервисных методов, там же описана библиотека MakeMeAsync, которой я с удовольствием и активно пользуюсь на данный момент. Не буду повторятся какие альтернативы существуют. Сейчас уже официально выпущен .Net Framework 4.5 c поддержкой конструкции async\await, так что я надеюсь что использование монструозных конструкций для выполнения кода асинхронно будет сходить на нет.

Думаю, что с вводным словом и актуализацией проблемы я справился, и можно уже приступить к рассмотрению самого тулкита.

Установка

Установка происходит с помощью NuGet, так же как и для многих других полезных библиотек в наше время:

PM> Install-Package Postsharp.Toolkit.Threading

Для работы тулкита достаточно базовой community лицензии PostSharp. После недолгой установки можно приступать к экспериментам.

Базовое использование

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

Я думаю, каждому разработчику с опытом более месяца с WPF, будет известен результат работы такого кода. При вызове метода Init() с интерфейса пользователя, произойдет замораживание окна на 2 секунды, после чего появится надпись из метода Finish().

С помощью рассматриваемого тулкита можно очень быстро привести «приложение» к надлежащему поведению. Для этого используется 2 атрибута:

  • BackgroundMethod – помечаются методы для запуска в фоновом режиме. Есть единственный параметр для отметки «долгоиграющих» методов: IsLongRunning.
  • DispatchedMethod – является указателем на то, что метод должен быть выполнен в контексте UI, будь то WinForms или WPF.

С их применением класс Model приобретает следующий вид:

Минимальные изменения, а сколько пользы в работе! Теперь приложение не зависает при работе долгоиграющих методов и корректно отображается и откликается на действия пользователя.

Теория работы

Описание на сайте PostSharp и дизасемблированный код ясно говорят о том, что при использовании атрибута BackgroundMethod, исходный метод попадает в обертку из простого Task. Т.е. в целом равноценен такому коду:

Прямо скажем небогато =) Но просто.

Второй атрибут, более сложен в реализации, но и ограничений у него несколько больше. При использовании атрибута необходимо, чтобы объект к методам которого применяется атрибут был создан в потоке UI. Дополнительно, в текущей реализации, атрибут может работать только с уже существующим контекстом синхронизации (SynchronizationContext). Т.е. контекст должен быть создан и инициализирован до того, как конструируется объект с методами помеченными атрибутом DispatchedMethod. Как правило это не проблема в реальных приложениях.

Параметр IsAsync указывает на принцип исполнения. Если он выставлен в true, то применяется принцип «запустил и забыл». По умолчанию значением является false.

Исключения

Исходя из способа реализации атрибута BackgroundMethod можно утверждать, что все исключительные ситуации пройдут мимо вас. Они не будут прокидываться до основного потока и не будут пойманы AppDomain.UnhandledException, так как это класс Task лежит в недрах атрибута.

Итого

Я бы не стал использовать данный тулкит в реальном энтерпрайз приложении из-за того, что нельзя получить исключения не в дебаг режиме. Однако для разных мелких утилит или же для приложений из разряда Proof of concept это вполне годная вещь.

Исходный код тулкита можно взять на github.

 

Hard’n’heavy!

 

 

 

Оставить комментарий