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中是否有类似的东西,或者是否有其他东西,可以使此类问题更容易处理?
您的区间中的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));
它非常干净,并且有助于显示如果未选中复选框则有空句号。