我在使用TakeUntil和IObservable的不同实现作为参数时会遇到不同的行为。我试图理解为什么我会得到不同的行为。使用Linqpad:
async Task Main()
{
var byTimer = true;
var ending = Observable.FromEvent<long>(
handler => endingHandler += handler,
handler => endingHandler -= handler);
var s = new Subject<long>();
using (var disposibleSub =
Observable
.Interval(TimeSpan.FromSeconds(.2))
.TakeUntil(byTimer ? Observable.Timer(TimeSpan.FromSeconds(1.5)) : ending)
.DumpLatest()
.Subscribe(Observer.Checked(s)))
{
if (endingHandler != null)
{
int r = Console.Read();
endingHandler?.Invoke(r);
}
var v = await s.Count();
Console.WriteLine("Count of items: {0}", v);
}
}
public event Action<long> endingHandler;
具有计时器Count的那个总是返回正确的值。但是,如果我将其更改为使用FromEvent实现,我总是得到0.显然不同之处在于两者的实现。我也尝试使用TakeUntil的Subject实现,其结果与fromEvent相同。
计时器结果符合我的预期。
解释为什么会受到赞赏!感谢。
答案 0 :(得分:1)
当byTimer
为true
时,ending
observable永远不会获得订阅 - 请记住,只有在订阅到达时才会实例化可观察的管道 - 所以在这种情况下{{1}附加事件代码不会运行,因此handler => endingHandler += handler
是endingHandler
。这意味着null
未被调用,因此代码会立即降至Console.Read()
,然后会捕获通过var v = await s.Count();
的所有值。
但是,当s
为byTimer
时,false
不 endingHandler
,则会调用null
。读取控制台后,立即调用Console.Read()
来停止观察,并在主题上调用endingHandler
。所以当它命中OnCompleted
时,它立即得到一个完整的信号,错过了所有先前产生的值,因此你得到的数量为零。
如果您将代码更改为:
var v = await s.Count();
然后两个可观测量的行为完全相同。
如果您还要将 int r = Console.Read();
if (endingHandler != null)
{
endingHandler?.Invoke(r);
}
var v = await s.Count();
更改为Subject
,那么代码的行为应该与您原来期望的一样。