如何在可观察到的反应式扩展中记住以前的有效载荷?



我有一个IObservable boolObservable,发布者就像开关一样。还有具有某些值的变量currentItem和包含预定义不可变值的默认Item。每当发布"true"时,都应记住当前项的值,并将当前项设置为默认项。发布"false"时,当前项的值应更改为前一个值。 实现此目的的最简单方法是使用局部变量。

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

可以使用扫描通过可观察序列线程化状态。例如:

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<bool>作为您的"开关",将一个IObservable<string>作为项目(在您的示例中currentItem(,并返回一个IObservable<string>,该将包含switchSource发出False时的defaultValueswitchSource发出True时的最后一个currentItem值。

注意:我可能倒退了currentlocal。已经晚了,你的例子巧妙地说明了为什么应该避免全局状态......推理起来实在是太棘手了。

最新更新