Skip to content

Instantly share code, notes, and snippets.

@MrAntix
Last active January 19, 2018 23:34
Show Gist options
  • Save MrAntix/1c1ad29e3733c90d312a90e99ba97828 to your computer and use it in GitHub Desktop.
Save MrAntix/1c1ad29e3733c90d312a90e99ba97828 to your computer and use it in GitHub Desktop.
Route events based on type on the same observable
public static class ObservableExtensions
{
public static Builder<TBase> SwitchType<TBase>(
this IObservable<TBase> observable)
{
return new Builder<TBase>(observable);
}
public class Builder<TBase>
{
readonly IObservable<TBase> _observable;
Func<TBase, Task<bool>> _onNext;
internal Builder(IObservable<TBase> observable)
{
_observable = observable;
_onNext = o => Task.FromResult(false);
}
public Builder<TBase> Case<TCase>(
Func<TCase, Task> action)
where TCase : class, TBase
{
var previousCheck = _onNext;
_onNext = async (TBase o) =>
{
if (await previousCheck(o)) return true;
return await IsType(o, action);
};
return this;
}
public Builder<TBase> Case<TCase>(Action<TCase> action)
where TCase : class, TBase
=> Case(ToAsync(action));
public IDisposable Subscribe(
Func<TBase, Task> defaultAction)
{
return _observable.Subscribe(async (TBase o) =>
{
if (await _onNext(o)) return;
await defaultAction(o);
});
}
public IDisposable Subscribe(Action<TBase> defaultAction)
=> Subscribe(ToAsync(defaultAction));
public IDisposable Subscribe()
{
return _observable.Subscribe(async e => await _onNext(e));
}
static async Task<bool> IsType<TCase>(TBase o, Func<TCase, Task> action)
where TCase : class, TBase
{
if (o is TCase)
{
await action(o as TCase);
return true;
}
return false;
}
static Func<T, Task> ToAsync<T>(
Action<T> action)
{
return o =>
{
action(o);
return Task.CompletedTask;
};
}
}
}
@MrAntix
Copy link
Author

MrAntix commented Jan 16, 2018

usage (obsolete see below)

myObservable.SubscribeSwitch()
    .Case<AnEvent>(e => { })
    .Case<AnOtherEvent>(e => { })
    .Else(e => { }))

@MrAntix
Copy link
Author

MrAntix commented Jan 19, 2018

The above worked because of the .Else(), which called the Observable.Subscribe() method explicitly.
Without this the implicit subscribe didn't work.

Opted for an explicit call to subscribe in the end which suits the pattern better anyway ie .Observable.SomeFunc().Subscribe()

usage

myObservable.SwitchType()
    .Case<AnEvent>(e => { })
    .Case<AnOtherEvent>(e => { })
    .Subscribe()

The .Else() action can be passed in to the .Subscribe(e => { }) as the default action

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment