返回一个Observable的Subscribe方法的Disposable

时间:2018-05-25 00:36:42

标签: c# reactive-programming system.reactive

我对本书的发布商子论坛上的Observables(which I posted)有疑问,但我仍在等待任何回复。

我使用提供的辅助方法作为标准做法而不是手工制作可观察对象。然而,出于学术兴趣,我确实看到了手工制作一个可观察者所需要的东西。

我在一本书中看到了一个实现,其中返回了订阅方法Disposable.Empty。 代码有点像下面。

public class MyObservable : IObservable<int>
{
    public IDisposable Subscribe(IObserver<int> observer)
    {
        for (int i = 0; i < 5; i++)
        {
            Thread.Sleep(1000);
            observer.OnNext(i);
        }
        observer.OnCompleted();
        return Disposable.Empty;
    }
}

如果我想返回一个正确的Disposable,它会在调用Dispose时实际导致取消订阅,应该是什么方式?

我对ObservableObserver使用此内容进行了解析

我不得不介绍订阅处理程序

public class SubscriptionHandler : IDisposable
{
    private readonly List<IObserver<int>> _listOfObservers;
    private readonly IObserver<int> _currentObserver;

    public SubscriptionHandler(List<IObserver<int>> currentListOfObservers, IObserver<int> currentObserver)
    {
        _listOfObservers = currentListOfObservers;
        _currentObserver = currentObserver;
    }

    public void Dispose()
    {
        if (_currentObserver != null && _listOfObservers.Contains(_currentObserver))
        {
            _listOfObservers.Remove(_currentObserver);
        }
    }
}

这是Observable的代码

public class MyObservable : IObservable<int>
{
    private List<IObserver<int>> _listOfSubscribedObservers = new List<IObserver<int>>();

    public IDisposable Subscribe(IObserver<int> observer)
    {
        if (!_listOfSubscribedObservers.Contains(observer))
        {
            _listOfSubscribedObservers.Add(observer);
        }

        Task.Run(() =>
        {
            for (int i = 0; i < 5; i++)
            {
                Thread.Sleep(1000);
                observer.OnNext(i);
            }

            observer.OnCompleted();
        });

        return new SubscriptionHandler(_listOfSubscribedObservers, observer);
    }
}

我有一种感觉,我错过了一些东西。必须有一种内置的方法来为手工制作的Observable返回一个有意义的Disposable,或者只有Observable才能创建辅助方法吗?

PS:如果低估请在评论中加入理由,这样我就可以避免在提问时重复出错。

2 个答案:

答案 0 :(得分:2)

我应该说清楚所有这些都是Rx设计内部的演示。你可以看一下班级AnonymousObservable<T>,  AnonymousObserver<T>AnonymousDisposable,这是框架的工作方式。挺直的。但是,您几乎不应该使用任何此类代码,而应使用Disposable.CreateObservable.Create之类的内容。如果您正在实施IObservable,那么您几乎肯定做错了。

这里有一个基本思想:可观察者需要产生一个IDisposable,它将相关的观察者从观察者的内部观察者名单中删除。您的代码(错误地)从内部列表中删除所有观察者。

这是一种基本的一次性产品,可以轻松创建功能。使用此代码,GenericDisposable.CreateDisposable.Create(Action a)相同。

public class GenericDisposable : IDisposable
{
    public static IDisposable Create(Action disposeAction)
    {
        return new GenericDisposable(disposeAction);
    }

    private readonly Action _disposeAction;
    public GenericDisposable(Action disposeAction)
    {
        _disposeAction = disposeAction;
    }
    public void Dispose()
    {
        _disposeAction();
    }
}

......这是一个可观察的实施示例:

public class SendIntMessages : IObservable<int>
{
    private readonly HashSet<IObserver<int>> _observers = new HashSet<IObserver<int>>();

    protected void OnNext(int i)
    {
        foreach (var o in _observers)
            o.OnNext(i);
    }

    protected void OnError(Exception e)
    {
        foreach (var o in _observers)
            o.OnError(e);
    }

    protected void OnCompleted()
    {
        foreach (var o in _observers)
            o.OnCompleted();
    }

    public void SendIntMessage(int i)
    {
        OnNext(i);
    }

    public void EndStream()
    {
        OnCompleted();
    }

    public void SendError(Exception e)
    {
        OnError(e);
    }

    public IDisposable Subscribe(IObserver<int> observer)
    {
        _observers.Add(observer);
        return GenericDisposable.Create(() => _observers.Remove(observer));
    }
}

这是一个长期,热烈的观察。它跟踪观察者,一次性取消订阅。

相反,可以观察到这一点:

public class CountTo5 : IObservable<int>
{
    public IDisposable Subscribe(IObserver<int> observer)
    {
        observer.OnNext(1);
        observer.OnNext(2);
        observer.OnNext(3);
        observer.OnNext(4);
        observer.OnNext(5);

        return GenericDisposable.Create(() => {});
    }
}

这是一个很冷的&#39;可观察的,立即运行。在中间没有办法取消订阅:当你拿到一次性用品时,观察者已经结束了。

Disposable.EmptyDisposableCreate(() => {})的简单简写。

答案 1 :(得分:0)

要将有意义的IDisposable返回给调用方,您不应在订阅期间同步生成所有通知。您应该在不同的上下文中异步生成它们,并立即将尚未完成的预订返回给调用方。通过使用Task.Run方法来调用ThreadPool上的通知,这是一种方法:

public class MyObservable : IObservable<int>
{
    public IDisposable Subscribe(IObserver<int> observer)
    {
        var cts = new CancellationTokenSource();
        _ = Task.Run(async () =>
        {
            for (int i = 0; i < 5; i++)
            {
                await Task.Delay(1000, cts.Token);
                observer.OnNext(i);
            }
            observer.OnCompleted();
        }, cts.Token);
        return new CancellationDisposable(cts);
    }
}

CancellationDisposable类...

代表具有关联CancellationToken的一次性资源,该资源将在处置后设置为取消请求状态。