【问题标题】:Observable from event可从事件观察
【发布时间】:2012-10-05 16:05:58
【问题描述】:

我是 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 获取信息?

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

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

这个分析大部分正确吗?

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

【问题讨论】:

  • 我也是 Rx 的新手。根据使用情况,我怀疑Where 不是必需的。
  • 对于过程中的任何步骤,您都可以手动注入 Do 方法并将结果输出到控制台(在 c++ 中这称为 printf 调试)。您可能还想试用visualrx.codeplex.com 工具以直观地查看运行时发生的情况。
  • @neontapri,如果在订阅时 IsLoaded 属性的值为 false,则 where 将删除 false 值,就像在 StartWith 运算符中一样。

标签: c# system.reactive


【解决方案1】:

大多数 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 提供信号,如果对象在订阅时已经加载。
  • 但是,如果对象未加载,IsLoaded 将为 false,Where 会将其过滤掉,当事件触发时会触发通知。
    • Select 将忽略事件产生的实际数据并简单地传递一个 true,这将通过 Where 过滤器。
  • Take 用于仅触发一次通知,无论它来自StartWith,因为对象已经加载,或者加载完成时事件(通过Select)。李>

【讨论】:

  • 正确。有问题的代码只是在加载对象(控件?)时生成单个值序列。如果它在订阅时已经加载,则立即推送一个值,否则将在加载时推送。
【解决方案2】:

如果您是 Rx 新手,并且需要了解每个运算符的功能,您可以尝试 Rx Sandbox - 它使用的是旧版本的 Rx,但您可能可以先从 v1 学习,然后再转到 v2。它允许您在流上可视化并尝试组合器,将结果显示为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()

【讨论】:

    猜你喜欢
    • 2015-10-18
    • 2017-12-12
    • 1970-01-01
    • 2018-07-29
    • 2016-05-18
    • 2012-07-24
    • 1970-01-01
    • 2016-10-12
    • 2016-12-11
    相关资源
    最近更新 更多