基于第三种方式在两个IObservable之间切换的最简单方法

时间:2013-02-07 03:25:56

标签: system.reactive

我有两个值流和一个选择器流,我想生成一个结果流,它根据选择器在值流之间交替。下面的代码给出了正确的结果,但我不喜欢它。

有没有人更整洁?

var valueStreamA = new BehaviorSubject<int>(0);
var valueStreamB = new BehaviorSubject<int>(100);
var selectorStream = new BehaviorSubject<bool>(true);

var filteredA = valueStreamA .CombineLatest(selectorStream, (a, c) => new { A = a, C = c })
  .Where(ac => ac.C)
  .Select(ac => ac.A);
var filteredB = valueStreamB.CombineLatest(selectorStream, (b, c) => new { B = b, C = c })
  .Where(bc => !bc.C)
  .Select(bc => bc.B);

var result = Observable.Merge(filteredA, filteredB);
result.Subscribe(Console.WriteLine);

valueStreamA.OnNext(1);
valueStreamB.OnNext(101);
selectorStream.OnNext(false);

valueStreamA.OnNext(2);
valueStreamB.OnNext(102);
selectorStream.OnNext(true);

这产生以下输出:

0
1
101
102
2

3 个答案:

答案 0 :(得分:2)

我会做这样的事情:

var a = new BehaviorSubject<int>(0);
var b = new BehaviorSubject<int>(100);
var c = new BehaviorSubject<bool>(true);

var valueStreamA = a as IObservable<int>;
var valueStreamB = b as IObservable<int>;
var selector = c as IObservable<bool>;

var result = selector
    // for every change in the selector...
    .DistinctUntilChanged()
    // select one of the two value streams
    .Select(change => change ? valueStreamA : valueStreamB)
    // and flatten the resulting wrapped observable
    .Switch();

result.Subscribe(Console.WriteLine);

a.OnNext(1);
b.OnNext(101);
c.OnNext(false);

a.OnNext(2);
b.OnNext(102);
c.OnNext(true);

答案 1 :(得分:0)

可以做类似的事情:

var xs = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => Feeds.Xs);
var ys = Observable.Interval(TimeSpan.FromSeconds(1)).Select(_ => Feeds.Ys);
var selectorSubject = new Subject<Feeds>();

var query = from selector in selectorSubject
                select from merged in xs.Merge(ys)
                where merged == selector
                select merged;

query.Switch().Subscribe(Console.WriteLine);

OnNext进入'selectorSubject'进行更改。 您的示例有一些差异,但很容易解决:

  1. 您的问题涉及bool类型的选择器,而我一直懒惰并重用Feeds枚举,以便允许我进行简单的相等检查(合并==选择器)。 你当然可以简单地做(选择器?merged == Xs:merged == Ys),或类似的东西来评估每个合并的项目并丢弃你不关心的项目(取决于你的选择器)。
  2. 具体来说,您可能不仅要选择整数,还要选择Feed的标识符。考虑使用像Tuple.Create()之类的东西,这样你就可以获得每次更新的信息: {A - 1},{B - 101}等等你可以在哪里做: 哪个选择器? merged.Item1 == A:merged.Item1 == B //这将'true'映射到Feed A

    1. 我还使用了Switch,它会导致我的样本流重新启动,因为它们没有发布。 您可能希望发布您的并将它们连接起来(让它们变得“热”),因此像我这样的Switch不会在订阅中引起任何新的副作用。你有一个主题(很热),但'behavior'部分将替换你传递给构造函数的值。发布和连接会阻止这种情况。
    2. 如果你仍然感到困惑,请大声喊叫。这不是一个完整的答案,但可能会给你足够的思考。

      霍华德。

答案 2 :(得分:0)

现在离你原来的问题更近了:

void Main()

{

var valueStreamA = new BehaviorSubject<int>(0);
var valueStreamB = new BehaviorSubject<int>(100);

var selectorStreamA = valueStreamA.Select(id => Tuple.Create("A", id)).Publish();
var selectorStreamB = valueStreamB.Select(id => Tuple.Create("B", id)).Publish();
var selectorStream = new BehaviorSubject<bool>(true);

var query = from selector in selectorStream
            select from merged in selectorStreamA.Merge(selectorStreamB)
                   where selector == true ? merged.Item1 == "A" : merged.Item1 == "B"
                   select merged.Item2;

query.Switch().Subscribe(Console.WriteLine);

selectorStreamA.Connect();
selectorStreamB.Connect();

//First we get 0 output (because we are already using stream A, and it has a first value)
valueStreamA.OnNext(1); //This is output, because our selector remains as 'A'
valueStreamB.OnNext(101); //This is ignored - because we don't take from B
selectorStream.OnNext(false); //Switch to B

valueStreamA.OnNext(2); //Ignored - we are now using B only
valueStreamB.OnNext(102); //This is output
selectorStream.OnNext(true); //Switch back to A.

}

输出:

0 1 102