Unity advanced или Awaitable компоненты-промисы

Приветствую! Сегодня я хотел бы поделиться своей наработкой, которую я создал около двух лет назад и использую в проектах и сегодня.

Оговорюсь, что все что описано ниже — придумано мной, так что идею я нигде не украл. Также в результате поисков в интернете ничего подобного не нашел. Если для вас это актуально — пользуйтесь на здоровье =)

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

А в силу того, что на дворе 2023 год, мы в след за js-ом сделаем этот промис awaitable. 

Я не буду останавливаться на работе async/await, по этому поводу и так достаточно много написано, не только на официальном сайте, но и много где в интернете. Обозначим только основные пункты.

Для обеспечения работы этого механизма от нас требуется в типе:

  • Реализовать INotifyCompletion 

  • Добавить IsCompleted свойство (bool)

  • Добавить метод GetResult (можно вернуть из него войд)

  • Реализовать метод GetAwaiter без параметров — возвращающий этот же тип (можно extension`ом) 

Также наш промис будет уметь принимать в себя параметры. 

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

Итак, начнём. Сначала опишем механизм приема параметров в самом компоненте. В нашем случае будет вот так:

Тут мы с помощью статики пробросим параметры для новых компонентов в этом же типе. В целом механизм очень простой — засовываем наши параметры в статику, а вводимый в среду компонент во время инициализации посмотрит в эту статику. Вся прелесть тут в методе Run, он понадобится нам в нашем компоненте-промисе.

Следующим шагом реализуем INotifyCompletion и все описанное выше:

Очень простой код. Немного его разберем — внесем ясность. Когда мы вызовем команду Run (с помощью await), мы добавим компонент, который вернется в методе GetAwaiter. Далее будет опрошено свойство IsCompleted, а за ним вызовется INotifyCompletion метод OnCompleted. Он вызовется до выполнения основного кода, и его параметр — это точка дальнейшего выполнения программы — мы должны будем запустить его самостоятельно, поэтому сохраним его. После того, как мы выполним все что хотели, нужно уничтожить компонент и продолжить выполнение программы. Сделаем это в сеттере свойства IsCompleted. 

Злые языки скажут: «А как же вернуть результат?» И мы вернем им результат:

Все, теперь у нас есть все необходимое для запуска компонента через ключевое слово await!(И все это занимает около 35 строк кода, не считая пробелов между строками)

Напишем наш первый awaitable компонент. Для удобства и простоты примера создадим таймер который отсчитает для нас 5 секунд.

Сразу отмечу, что можно не только писать awaitable таймеры, можно  показывать попапы, открывать сцены и т.д. В такой записи все, что может быть выражено компонентом, может быть выполнено в await стиле.

У нас есть архитип, есть его конкретные дочерние объекты, осталось только запустить их. Сделаем это:

Вот и все. Логи будут выведены с интервалом в пять секунд. Надеюсь Вам понравилось и этот подход найдет свое применение на ваших проектах. Спасибо за внимание!


ссылка на оригинал статьи https://habr.com/ru/post/713146/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *