可按事件查看的完整IO

时间:2018-12-20 09:26:02

标签: c# system.reactive

有一种方法可以使用Observable.FromEvent将事件包装为可观察的事件。例如。这个课:

class Generator<T>
{
    event Action<T> onPush;

    public IObservable<T> Items =>
        Observable.FromEvent<T>(d => onPush += d, d => onPush -= d);

    public void Push(T item) => onPush?.Invoke(item);
}

但是,我还没有找到一种通过事件来完成可观察对象的方法-我该怎么做?

更新

为弄清我的意思,上面的类产生IObservable<T>,它是“无尽的”且永远不会完成。我想使它由另一个事件完成,而不是使另一个事件可观察。因此问题可以简化为:

如何提前完成任意IObservable<T>,即要调用的OnCompleted通知?

1 个答案:

答案 0 :(得分:2)

可观察对象表示通知或事件流。当可观察到的事件来源时,它们本质上是无止境的。可观察对象连接到事件,并引用对象,因此支持事件的对象永远不会超出范围。 .NET / C#没有提供指示事件不再被调用的方法,因此直接连接到该事件的可观察对象是无止境的。

这并不罕见;大多数基于事件的可观察对象从未OnCompleted被显式调用,无法在真实世界中建模,很难确切地说某些事情将不再发生。

但是,这不是问题:可观察对象可以无限运行,并且不会造成损坏。取消订阅的可观察对象不会占用太多资源。如果您对基于事件的可观察对象不感兴趣,请取消订阅所有订阅,就可以了。

一种方法是使用Take运算符之一,例如TakeUntil运算符(如下所述)。尝试以下代码(使用您的Generator类):

var g = new Generator<int>();
g.Items
    .TakeUntil(i => i > 3)
    .Subscribe(
        i => Console.WriteLine($"OnNext: {i}"), 
        e => Console.WriteLine($"OnError: Message: {e.Message}"), 
        () => Console.WriteLine("OnCompleted")
    );

g.Push(1);
g.Push(2);
g.Push(3);
g.Push(4);
g.Push(5);
g.Push(6);

输出:

OnNext: 1
OnNext: 2
OnNext: 3
OnNext: 4
OnCompleted
在出现大于3的整数的消息后,

TakeUntilItems取消订阅。这就是为什么有OnCompleted且没有5、6条消息的原因。

此外,正如谜语所述,您的Generator<T>类与Subject<T>基本相同,我建议您使用它。


原始答案:

从事件中观察到另一个,然后使用.TakeUntil

class Generator<T>
{
    event Action<T> onPush;
    event Action<Unit> onCompleted;

    public IObservable<T> Items =>
        Observable.FromEvent<T>(d => onPush += d, d => onPush -= d)
        .TakeUntil(Completion);

    public IObservable<Unit> Completion =>
        Observable.FromEvent<Unit>(d => onCompleted += d, d => onCompleted -= d);

    public void Push(T item) => onPush?.Invoke(item);
    public void Complete() => onCompleted?.Invoke(Unit.Default);
}