2. Минусы событий .NET
•Требует указания конкретного делегата
•Затрудняет использование лямбд
•Провоцирует утечки ресурсов
Отписка
• Обработка событий с учетом временных зависимостей
крайне затрудненаУчет времени
•Для потока данных есть LINQ, а для потока событий это
невозможно – событие не значение первого классаКомпозиция
•В каком контексте будет выполнятся обработчик – зависит от
событияСинхронность
3. События как интерфейсы
•Это источник событий, аналог event
•Единственный метод – подписка : IDisposable Subscribe( IObserver<T> observer )
•Отписка, если нужна – простым вызовом Dispose
IObservable<T>
•Это приемник событий, аналог IEventHandler из нашего Delphi-фреймворка
•Основной метод – обработка события void OnNext(T value )
•Уведомление, что событий больше не будет void OnCompleted()
• Уведомление, что об ошибке в источнике void OnError(Exception error )
IObserver<T>
•Событие как интерфейс - значение первого класса
•Можно использовать с using
•Знакомый классический паттерн банды четырех после нашего фреймворка Delphi и
Java
Плюсы
•Методы Subscribe и Dispose должны быть потокобезопасными
•Наблюдатель не должен выбрасывать исключения из своих реализаций методов
•Не рекомендуется отменять регистрацию в реализации Subscribe
•Не рекомендуется подписывать одного наблюдателя на несколько потоков событий
Требования
4. Да будет LINQ!
• Поток событий – аналог потока данных
• GetEnumerator = Subscribe
• Current = OnNext + OnException
• !MoveNext = OnComplete
• Dispose = subscribe.Dispose
IEnumerable
IObservable
• LINQ для событий возможен, как и для любых значений первого класса
• По семантике LINQ для потоков событий похож на LINQ для коллекций
• Только в самом фреймворке ничего такого нет
LINQ2events
• Готовые универсальные реализации IObservable и IObserver
• При подписке можно просто указывать обработчики, а также токен отмены
• Реализация LINQ для IObservable
• Поддержка асинхронности, параллелизма и конвертации в привычные
сущности (последовательности, события, задачи, асинхронные вызовы) и
обратно
Reactive
Extensions
5. Особенности потоков событий
•Для событий в одном потоке задано отношение полного порядка
– одно событие раньше, другое - позже
•Новое событие не будет передано подписчикам до окончания
обработки предыдущего
Упорядоченность
•У события есть время возникновения
•ToInterval добавляет время между событиями
•Throttle исключает частые события
•Множество других фильтров и комбинаторов с учетом времени
Темпоральность
•Возникновение события в общем случае не привязано к
текущему контексту
•Поток событий – аналог асинхронного вызова для множества
возвращаемых результатов
Асинхронность
6. Генераторы событий
Статические методы Observable
•Return – ровно одно событие
•Empty – ни одного события, сразу конец
•Throw – сразу ошибка
•Never – абсолютная тишина, ни одного вызова
Примитивные
•Range – аналогично как и для IEnumerable
•Generate – аналог цикла forПоследовательные
•Timer – одно событие в указанное время или через
указанный временной интервал
•Interval – события с указанным временным интервалом
между ними
Временные
7. Горячие и холодные источники
• Генерируют события только при подписке
• Выдают каждому подписчику все сообщения с самого начала
• Пример – ранее приведенные генераторы
Холодные
• Генерируют события независимо от наличия подписчиков
• Выдают подписчикам события только в период подписки, разделяя
каждое сообщение между всеми подписчиками
• Пример – события от клавиатуры и мыши
Горячие
• Метод расширения Publish возвращает горячий источник, позволяя
разделять одну подписку на холодный между несколькими
наблюдателямиРазогрев
8. Планировщики
• Sheduler.Immediate – немедленное выполнение без планирования
• Scheduler.CurrentThread – c контролем deadlock’овОднопоточные
• Scheduler.NewThread – выполнение в новом потоке
• Scheduler.TaskPool – выполнение в TPL.Task
• Scheduler.ThreadPool – выполнение в пуле потоков
Многопоточные
• DispatcherScheduler – выполнение в потоке UI для WPF/Silverlight
• ControlScheduler – то же для WinFormsUI
• Автоматический – ничего указывать не надо, будет выбран наиболее
подходящий
• В LINQ – можно явно указать для последовательности с помощью метода
ObserveOn
Выбор
9. Мосты
• Методы ToObservale и ToEnumerable
• Все стандартные ToXXX методы LINQ
Последовательности и
коллекции
• Метод FromEventPattern
• Можно указать методы для подписки и отписки
• Для событий по шаблону EventHandler можно указать имя (найдется с
помощью отражения)
События
• Метод FromAsyncPattern
• Превращает вызов в поток событий с одним элементом - результатомАсинхронные вызовы
• Метод расширения для задачи ToObservable
• Метод расширения для источника ToTask (вернет последнее значение)
• Задача от источника событий отличается только количеством результатов
Задачи
10. Drag & Drop
• var mousedown = from evt in
Observable.FromEvent<MouseButtonEventArgs>(this, "MouseDown")
select evt.EventArgs.GetPosition(this);
Нажатия
• var mouseup = from evt in
Observable.FromEvent<MouseButtonEventArgs>(this, "MouseUp" )
select evt.EventArgs.GetPosition(this);
Отпускания
• var mousemove = from evt in
Observable.FromEvent<MouseEventArgs>(this, "MouseMove" )
select evt.EventArgs.GetPosition(this);
Перемещения
• var q = from start in mousedown from pos in
mousemove.StartWith(start).TakeUntil(mouseup)
select pos;
Перетаскивание
• q.ObserveOnDispatcher().Subscribe(
value => textBlock.Text = value.ToString());Обновление UI
11. Асинхронный вызов
• Используется метод расширения using, гарантирующий
вызов Dispose после завершения потока событий
• Observable.Using(() => new WCFServiceClient()
Автоочистка
ресурсов
• , client => Observable.
FromAsyncPattern<RequestType, ResponseType>(
client.BeginWCFMethod,
client.EndWCFMethod)(request))
Конвертация
вызова
• .Subscribe(
response => response.List.ForEach(WriteOutBusiness),
ex => Console.WriteLine("Error = " + ex.Message),
() => Console.WriteLine("Completed."));
Обработка
результата
12. Источники вдохновения
1. Шаблон разработки Observer
2. Композиционный стиль программирования с
Reactive Extensions (презентация)
3. Библиотека реактивных расширений (видео)
4. Creating and Subscribing to Simple Observable
Sequences
5. Jesse Liberty – Reactive
6. “Реактивные расширения” и асинхронные
операции