从事件可观察到

时间:2012-10-05 16:05:59

标签: c# system.reactive

我是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 将只取序列的第一个值(在这种情况下不再使用)。然后订阅,只有在加载控件时才会写入控制台。

这种分析大多是正确的吗?

此外,有关调试此类事物的任何提示(意味着,在链的不同阶段,序列是什么样的)?我可以通过附加调试器来获取信息,但我想知道是否还有其他可能常用的技巧/提示。

2 个答案:

答案 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运算符的表示。

Rx Marble Diagram Viewer

很容易看出它从两个流中配对了两个值。

调试序列的一种简单方法是在中间使用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()