2

我是 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如何将Loaded事件转换为可观察的序列。现在,Select将在IsLoaded为真时触发(这就是我的假设)。Select是否只是从 RoutedEventArgs 获取信息?

现在,我不确定为什么StartsWith在那里。 StartsWith会将一系列值添加到可观察序列中。那么它只是将IsLoaded的值添加到列表的开头吗?Select发生后它不是已经存在了吗?

.Where没有应用任何类型的过滤器,因此.Take将只取序列的第一个值(在这种情况下不再使用)。然后它订阅并仅在加载控件时写入控制台。

这种分析大部分正确吗?

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

4

2 回答 2

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,做这种事情没有多大意义,因为您总是会得到一个为真的值(除非源数组为空且 IsLoaded 为假)。

将 this 与 IObservable 一起使用是为了在加载对象时生成一个信号。

  • StartWith如果对象在订阅时已经加载,则提供信号。
  • 但是,如果对象未加载,则为IsLoadedfalse,Where会将其过滤掉,当事件触发时,会触发通知。
    • Select忽略事件产生的实际数据,并简单地传递一个 true,它将继续通过Where过滤器。
  • 用于仅触发一次通知,Take无论它来自StartWith,因为对象已经加载,或者Select加载完成时的事件(通过 )。
于 2012-10-05T16:26:28.427 回答
2

如果您是 Rx 新手,并且需要了解每个操作员的工作内容,您可以尝试Rx Sandbox - 它使用旧版本的 Rx,但您可能可以先从 v1 学习,然后再转到 v2。它允许您可视化并尝试流上的组合器,将结果显示为大理石图

这是Zip运算符的表示。

Rx Marble 图表查看器

很容易看出它将两个流中的两个值配对。

调试序列的一种简单方法是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()
于 2012-10-06T05:57:01.780 回答