我是Rx的新手并且正在浏览一些样本并且遇到了以下内容:
Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(
h => new RoutedEventHandler(h),
h => Loaded += h,
h => Loaded -= h)
.Select(_ => true)
.StartWith(IsLoaded)
.Where(l => l)
.Take(1)
.Subscribe(_ => Console.WriteLine("loaded");
我试图解构这个陈述以弄清楚它在做什么,但对我来说并非100%清楚。
我理解 FromEventPattern 如何将已加载事件转换为可观察序列。现在, IsLoaded 为真时会触发选择(这就是我假设的)。 选择只是从RoutedEventArgs获取信息吗?
现在,我不确定为什么 StartsWith 。 StartsWith 会将一系列值添加到可观察序列中。那么只是将 IsLoaded 的值添加到列表的开头? 选择后会不会出现?
。没有应用任何类型的过滤器,所以 .Take 将只取序列的第一个值(在这种情况下不再使用)。然后订阅,只有在加载控件时才会写入控制台。
这种分析大多是正确的吗?
此外,有关调试此类事物的任何提示(意味着,在链的不同阶段,序列是什么样的)?我可以通过附加调试器来获取信息,但我想知道是否还有其他可能常用的技巧/提示。
答案 0 :(得分:4)
大多数Observable运算符的工作方式与同名的Enumerable运算符相同。如果您有使用它们的经验,那么它将非常有用。
因此,为了解决这个问题,让我们暂时使用一个整数数组而不是observable。
int[] data = {1, 2, 3, 4};
这会将表达式更改为
var results = data.Select(_ => true)
.StartWith(IsLoaded)
.Where(l => l)
.Take(1);
foreach (var r in results)
{
Console.WriteLine("loaded");
}
如果您在表达式的每个阶段创建了一个数组,那么:
Select - {true, true, true, true}
StartWith - {value of IsLoaded, true, true, true, true}
Where - (if IsLoaded is true) {true, true, true, true, true}
(if IsLoaded is false) {true, true, true, true}
Take - {true}
使用IEnumerables,执行此类操作没有多大意义,因为您将始终获得一个为true的值(除非源数组为空且IsLoaded为false)。
将此与IObservable一起使用是为了在加载对象时产生一个会产生一个信号的东西。
StartWith
将提供信号。IsLoaded
将为false,Where
会将其过滤掉,并且当事件触发时,它将触发通知。
Select
将忽略事件产生的实际数据,只需传递一个true,它将继续通过Where
过滤器。Take
仅用于触发通知一次,无论它来自StartWith
,因为对象已加载,或事件(通过Select
),加载完成时。答案 1 :(得分:1)
如果你是Rx的新手,并且需要清楚每个操作员的操作,你可以尝试Rx Sandbox - 它使用旧版本的Rx,但是你可以在继续阅读v2之前从v1中学习。它允许您在流上可视化和试用组合器,以marble diagram显示结果。
以下是Zip
运算符的表示。
很容易看出它从两个流中配对了两个值。
调试序列的一种简单方法是在中间使用Do
运算符,如下所示:
static IObservable<T> Log<T>(this IObservable<T> stream, string name)
{
return stream.Materialize()
.Do(n => Console.WriteLine("{0} - {1}",name, n))
.Dematerialize();
}
示例:
Observable.Interval(TimeSpan.FromSeconds(0.5))
.Log("Timer")
.Where(i => i % 2 == 0)
.Log("Where")
.Sample(TimeSpan.FromSeconds(2))
.Log("Sample")
.Take(1)
.Log("Take")
.Subscribe();
您可以看到每个值在管道中传播:
Timer - OnNext(0)
Where - OnNext(0)
Timer - OnNext(1)
Timer - OnNext(2)
Where - OnNext(2)
Timer - OnNext(3)
Sample - OnNext(2)
Take - OnNext(2)
Take - OnCompleted()