使用System.Reactive.Linq订阅首次出现事件并取消

时间:2017-04-12 10:38:08

标签: c# system.reactive

给定来自事件流的IObservable序列:

IObservable<MyEvent> observable = EventAggregator.GetEvent<MyEvent>()

我第一次出现事件:

MyEvent myEvent = await observable.FirstOrDefaultAsync();

然而,我想要处理订阅,resp。当用户点击取消按钮时,中断observable。

目前我使用.ToTask()扩展方法的解决方法,但我相信只有基于Rective扩展的更清晰的解决方案。

_tsc = new CancellationTokenSource();
MyEvent myEvent;
try
{
    myEvent = await EventAggregator.GetEvent<MyEvent>()
        .FirstOrDefaultAsync()
        .ToTask(__tsc.Token);
}
catch (TaskCanceledException)
{
    myEvent = null;
}


void Cancel()
{
    _tsc.Cancel();
}

2 个答案:

答案 0 :(得分:1)

我不确定这是&#34;更干净&#34;,但你可以在没有ToTask的情况下做到这一点:

static async void Test(IObservable<int> ob, CancellationToken ct)
{
    var first = await ob.TakeUntil(Observable.Create<Unit>(o => ct.Register(() => {
            o.OnNext(Unit.Default);
            o.OnCompleted();
    }))).FirstOrDefaultAsync();            
} 

因此我们创建另一个observable,当取消令牌被取消时将生成一个元素,然后我们使用TakeUntil重载,它将从第一个序列返回元素,直到第二个序列生成一个元素。因此,在您取消令牌后 - 您的await语句将返回默认值(null作为参考类型)。

您可以将其移至扩展方法,然后它会更好看:

public static class Extensions {
    public static IObservable<T> TakeUntilCancelled<T>(this IObservable<T> ob, CancellationToken ct) {
        return ob.TakeUntil(Observable.Create<Unit>(o => ct.Register(() =>
        {
            o.OnNext(Unit.Default);
            o.OnCompleted();
        })));
    }
}

var first = await ob.TakeUntilCancelled(ct).FirstOrDefaultAsync();      

答案 1 :(得分:0)

使用内置的Rx操作符,您想要做的事情非常简单。

这样做:

IObservable<MyEvent> observable = EventAggregator.GetEvent<MyEvent>()
var endItAll = new Subject<Unit>();
MyEvent myEvent = await observable.TakeUntil(endItAll).FirstOrDefaultAsync();

现在,您只需致电endItAll.OnNext(Unit.Default)即可结束订阅并返回null MyEvent