У вас вообще есть правильная идея, на самом деле.Вам просто нужно сделать фактическую отправку.В этом поможет SelectMany:
class Bus
{
Subject<Command> commands;
Subject<Invocation> invocations;
// TODO: Instantiate me
List<Func<Command, bool>> handlerList;
public Bus()
{
this.commands = new Subject<Command>();
this.invocations = new Subject<Invocation>();
commands.SelectMany(x => {
// This FirstOrDefault() is just good ol' LINQ
var passedHandler =
handlerList.FirstOrDefault(handler => handler(x) == true);
return passedHandler != null ?
Observable.Return(new Invocation() { Command = x, Handled = true}) :
Observable.Throw<Invocation>(new Exception("Unhandled!"));
}).Multicast(invocations).Connect();
}
/* ... snip ... */
}
Но, если честно, это не совсем демонстрирует мощь Rx, потому что он выполняет список обработчиков синхронно.Давайте сделаем это более убедительным, сделав его полностью неблокирующим.
Во-первых, мы изменим наш прототип Func на Func<Command, IObservable<Invocation>>
.Это означает, что метод принимает команду и выдает результат Future Invocation (a-la Task<T>
).Затем мы можем получить идентичное поведение, но при этом наши селекторы будут асинхронными с помощью этого селектора (кодирование через TextArea впереди):
commands.SelectMany(x =>
handlerList.ToObservable()
.Select(h => Observable.Defer(() => h(x)))
.Concat()
.SkipWhile(x => x.Handled == false)
.TakeLast(1))
.Multicast(invocations).Connect();
Это довольно хорошее использование Rx на уровне выпускника, но идея заключается в том, что для каждогоКоманда, мы собираемся сначала создать поток обработчиков и запустить их по порядку (это то, что делает Defer + Concat), пока мы не найдем тот, у которого Handled - true, а затем возьмем последний.
Внешний SelectMany выбирает поток команд в поток будущих результатов (т. Е. Тип IO<IO<Invocation>>
, а затем сглаживает его, так что он становится потоком результатов.
Нет блокировки никогда,очень лаконичный, на 100% тестируемый, типобезопасный код, который просто выражал довольно сложную идею, которую было бы очень уродливо писать настоятельно. Вот почему Rx - это круто.