【问题标题】:How to memorize previous payload in reactive extensions observable?如何在可观察的反应式扩展中记住以前的有效负载?
【发布时间】:2020-06-13 14:53:31
【问题描述】:

我有一个 IObservable boolObservable,发布者的行为就像 switch。还有带有一些值的变量 currentItem 和包含预定义不可变值的 defaultItem。每当发布 'true' 时,应记住 currentItem 的值,并且应将 currentItem 设置为 defaultItem。发布“false”时,currentItem 的值应更改为之前的值。 实现这一点的最简单方法是使用局部变量。

IObservable<bool> boolObservable;
string currentItem;
string defaultItem;

string local = null;
boolObservable.Subscribe(x =>
  {
    if (x) {
      local = currentItem;
      currentItem = defaultItem;
    }
    else
      currentItem = local;
  });

当我必须多次重复此操作并且每次都以不同的方式命名用于存储的局部变量时,问题就开始了。有没有办法使用 Rx 操作符来“记住”不仅是最新的有效载荷,而且是之前的有效载荷?

UPD:@ibebbs 下面的回答绝对正确,Scan 运算符提供了必要的行为:

var switchSource = new BehaviorSubject<bool>(false);
string currentItem = "FromDb";
string defaultItem = "Default";

switchSource
    .Skip(1)
    .Scan(string.Empty, (local, b) =>
    {
        if (b)
        {
            local = currentItem;
            currentItem = defaultItem;
        }
        else
            currentItem = local;

        return local;
    })
    .Subscribe();

Console.WriteLine($"Initial value: {currentItem}"); // FromDb
switchSource.OnNext(true);
Console.WriteLine($"Default value: {currentItem}"); // Default
switchSource.OnNext(false);
Console.WriteLine($"Initial value again: {currentItem}"); // FromDb
currentItem = "UserChanged";
Console.WriteLine($"UserChanged value: {currentItem}"); // UserChanged
switchSource.OnNext(true);
Console.WriteLine($"Default value: {currentItem}"); // Default
switchSource.OnNext(false);
Console.WriteLine($"UserChanged value again: {currentItem}"); // UserChanged

【问题讨论】:

  • currentItem 的值最初来自哪里?它也是一个可观察的来源吗?当“开关”设置为使用默认值时,currentItem 应该如何更改(或不更改)?解决方案可能是一个简单的CombineLatest(),但很难说。请添加某种图表,说明应在何处/何时设置哪个值以及这些值如何随时间变化。
  • @Progman currentItem 最初来自数据库。当 boolObservable 的源 BehaviorSubject 值设置为 false 时,用户也可以更改它。否则无法更改。它实际上被视为一个简单的可变属性,但也可以转换为 IObservable

标签: c# system.reactive


【解决方案1】:

您可以使用Scan 通过可观察序列来线程化状态。例如:

public static IObservable<string> EitherItemOrDefault(IObservable<bool> switchSource, IObservable<string> itemSource, string defaultValue)
{
    return switchSource
        .WithLatestFrom(itemSource.StartWith(string.Empty), (switchValue, itemValue) => (Switch: switchValue, Item: itemValue))
        .Scan(
            (Current: string.Empty, Local: string.Empty),
            (seed, tuple) => tuple.Switch 
                            ? (Current: defaultValue, Local: tuple.Item) 
                            : (Current: seed.Local, Local: seed.Local))
        .Select(tuple => tuple.Current);
}

这将IObservable&lt;bool&gt; 作为您的“开关”,将IObservable&lt;string&gt; 作为项目(在您的示例中为currentItem)并返回一个IObservable&lt;string&gt;,当switchSource 发出一个@ 时,它将包含defaultValue 987654329@ 和最后一个 currentItem 值,当 switchSource 发出 True 时。

注意:我可能有 currentlocal 倒退。已经很晚了,您的示例巧妙地说明了为什么应该避免全局状态......这很难推理。

【讨论】:

  • 谢谢,Scan 运算符正是我要找的。​​span>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-26
  • 1970-01-01
相关资源
最近更新 更多