Rx中的时变值

本文关键字:Rx | 更新日期: 2023-09-27 18:09:35

我有两个可观察对象。一个来自Observable.fromEvent(..),其中底层事件是用户选中Winforms复选框。另一个是Observable.Interval(..),我订阅它是为了做一些IO,我想阻止这个可观察对象做IO,只要复选框没有被选中。

我可以这样做:

var gui = new GUI();
var booleans = Observable
    .FromEvent<GUI.NewAllowHandler, bool>(
        h => gui.NewAllow += h,
        h => gui.NewAllow -= h)
Observable.Interval(TimeSpan.FromSeconds(10))
          .CombineLatest(booleans, Tuple.Create)
          .Where(t => t.Item2)
          .Select(t => t.Item1)
          .Subscribe(l => DoStuff(l));

,但这有在流内外混合布尔值的开销。一种更好的方法是,如果我可以从booleans变量生成一个时变值,它总是具有最后一个事件的值。然后我可以这样写:

var gui = new GUI();
var booleanState = Observable              // typeof(booleanState) == ???
    .FromEvent<GUI.NewAllowHandler, bool>(
        h => gui.NewAllow += h,
        h => gui.NewAllow -= h)
    .TimeValue()                           // hypothetical syntax

Observable.Interval(TimeSpan.FromSeconds(10))
          .Where(_ => booleanState) 
          .Subscribe(l => DoStuff(l));

,在我看来更接近问题陈述。在Rx中是否有类似的东西,或者是否有其他东西,可以使此类问题更容易处理?

Rx中的时变值

您的区间中的Where语句应该使用适当范围的正常bool:

var booleans = Observable
    .FromEvent<GUI.NewAllowHandler, bool>(
        h => gui.NewAllow += h,
        h => gui.NewAllow -= h)
var isBoxChecked = false;
booleans.Subscribe(t => isBoxChecked = t);
Observable.Interval(TimeSpan.FromSeconds(10))
    .Where(_ => isBoxChecked)
    .Subscribe(l => DoStuff(l))

编辑:根据你的评论,另一种做法:

intervals = Observable.Interval(TimeSpan.FromSeconds(10));
booleans
    .Where(t => t)
    .SelectMany(_ => intervals.TakeUntil(booleans))
    .Subscribe(l => DoStuff(l))

您需要将复选框选中状态建模为行为,而不是事件流(因为行为总是有一个值,并且这个值在一段时间内变化-这与复选框选中状态相匹配)。所以你可以这样做:

var booleans = new BehaviorSubject<bool>(chk.Checked)
var chkEvents = ... //generate boolean observable from checkbox check event
chkEvents.Subscribe(booleans);
Observable.Interval(TimeSpan.FromSeconds(10))
 .Where(i => booleans.First())
 .Subscribe(i => DoIO());

我将给出两种解决方案。第一种方法非常简单,希望很明显,只使用一个可观察对象。第二个是a同时使用两个可观察对象。

由于您希望仅在选中复选框时才允许IO,因此这是最简单的方法:

Observable
    .Interval(TimeSpan.FromSeconds(10))
    .Where(_ => gui.IsChecked)
    .Subscribe(l => DoStuff(l));

不需要其他可观察对象

但是如果你真的需要使用它,那么Switch()扩展方法是你最好的选择。试试这个:

booleans
    .Select(b => b == true
        ? Observable.Interval(TimeSpan.FromSeconds(10)) 
        : Observable.Empty<long>())
    .Switch()
    .Subscribe(l => DoStuff(l));

它非常干净,并且有助于显示如果未选中复选框则有空句号。

相关文章:
  • 没有找到相关文章