如何防止Scan多次运行?

时间:2015-06-04 14:58:00

标签: .net system.reactive reactive-programming

例如

var subject = new Subject<int>();
var test = subject.Scan(0, (x, y) => {
    Console.WriteLine("scan");
    return x + 1;
});
test.Subscribe(x => Console.WriteLine("subscribe1"));
//test.Subscribe(x => Console.WriteLine("subscribe2"));
Observable.Range(0, 1).Subscribe(subject);
Console.WriteLine("done");
Console.Read();

输出

scan
subscribe1
done

但如果你取消注释第二个订阅输出是

scan
subscribe1
scan
subscribe2
done

为什么扫描会运行两次,我该如何预防? 所以输出应该是

scan
subscribe1
subscribe2
done

我使用Subject来积累不同的Observable。然后我使用Scan方法更新Model,然后我有不同的地方需要订阅Model更新。也许没有使用主题有更好的解决方案吗?

2 个答案:

答案 0 :(得分:3)

尝试使用Observable.Publish获取IConnectableObservable<T>

var subject = new Subject<int>();
var test = subject
    .Scan(0, (x, y) => {
        Console.WriteLine("scan");
        return x + 1;
    })
    .Publish();
test.Subscribe(x => Console.WriteLine("subscribe1"));
test.Subscribe(x => Console.WriteLine("subscribe2"));
test.Connect();
Observable.Range(0, 1).Subscribe(subject);
Console.WriteLine("done");
Console.Read();

输出:

scan
subscribe1
subscribe2
done

Publish将冷Scan可观察变为热观察,在调用Connect时开始发出值。

答案 1 :(得分:1)

您看到的问题是Subject是一个热门观察者,而Scan每次订阅时都会创建一个新的冷观察者。

尝试在主题之前移动扫描

var subject = new Subject<int>();
subject.Subscribe(x => Console.WriteLine("subscribe1"));
subject.Subscribe(x => Console.WriteLine("subscribe2"));
Observable.Range(0, 1).Scan(0, (x, y) => {
    Console.WriteLine("scan");
    return x + 1;
}).Subscribe(subject);
Console.WriteLine("done");
Console.Read();

您也可以在没有Subject的情况下执行此操作:

var test = Observable.Range(0, 1).Scan(0, (x, y) => {
    Console.WriteLine("scan");
    return x + 1;
}).Publish();

test.Subscribe(x => Console.WriteLine("subscribe1"));
test.Subscribe(x => Console.WriteLine("subscribe2"));
test.Connect();

Console.WriteLine("done");
Console.Read();

Hot vs Cold Observables