C# 从Subscribe方法返回可观测的

C# 从Subscribe方法返回可观测的,c#,reactive-programming,system.reactive,C#,Reactive Programming,System.reactive,我有一个关于可观性的问题(关于这本书的出版商分论坛,但我仍在等待任何回应) 我使用提供的助手方法作为标准实践,而不是手工制作观测值。然而,出于学术兴趣,我确实了解了手工制作一个可观察物体需要什么 我在一本书中看到了一个实现,在subscribe方法Disposable.Empty的末尾返回了这个实现。 代码如下所示 public class MyObservable : IObservable<int> { public IDisposable Subscribe(IObse

我有一个关于可观性的问题(关于这本书的出版商分论坛,但我仍在等待任何回应)

我使用提供的助手方法作为标准实践,而不是手工制作观测值。然而,出于学术兴趣,我确实了解了手工制作一个可观察物体需要什么

我在一本书中看到了一个实现,在subscribe方法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;
    }
}
公共类MyObservable:ioobservable
{
公共IDisposable订阅(IObserver观察员)
{
对于(int i=0;i<5;i++)
{
睡眠(1000);
观察员OnNext(一);
}
observer.OnCompleted();
返回一次性。空;
}
}
如果我想退回一个合适的一次性产品,而这实际上会导致在调用Dispose时取消订阅,那么应该怎么做

我试着用这个做这个,用这个做这个

我必须引入一个订阅处理程序

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);
        }
    }
}
    
公共类SubscriptionHandler:IDisposable
{
私有只读列表_ListofObserver;
专用只读IObserver\u currentObserver;
公共SubscriptionHandler(列表CurrentListofObserver,IObserver currentObserver)
{
_ListofObserver=当前ListofObserver;
_currentObserver=currentObserver;
}
公共空间处置()
{
如果(_currentObserver!=null&&u ListofObserver.Contains(_currentObserver))
{
_移除(_currentObserver);
}
}
}
这是可观察的代码

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);
    }
}
公共类MyObservable:ioobservable
{
私有列表_ListofSubscribedObserver=新列表();
公共IDisposable订阅(IObserver观察员)
{
if(!\u订阅的观察者列表包含(观察者))
{
_订阅的观察者列表。添加(观察者);
}
Task.Run(()=>
{
对于(int i=0;i<5;i++)
{
睡眠(1000);
观察员OnNext(一);
}
observer.OnCompleted();
});
返回新的SubscriptionHandler(_ListofSubscribedObserver,observer);
}
}

我觉得我错过了什么。必须有一种内置的方法来返回手工制作的可观察的有意义的一次性文件,或者这是只有可观察的创建助手方法才能实现的?

我应该明确指出,所有这些都是Rx设计内部的演示。你可以看看课程, ,这就是框架的工作方式。非常直截了当。但是,您几乎不应该使用这些代码中的任何一个,而应该使用像
一次性的.Create
可观察的.Create
这样的东西。如果您正在实现一个
IObservable
,那么几乎肯定是做错了

基本思想如下:被观察者需要生成一个
IDisposable
,它从被观察者的内部观察者列表中删除相关的观察者。您的代码(错误地)从内部列表中删除了所有观察者

这是一个基本的一次性产品,可以很容易地创建功能。使用此代码,
GenericDisposable.Create
Disposable.Create(操作a)
相同

…下面是一个可观察的实现示例:

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));
    }
}
公共类SendIntMessages:IObservable
{
私有只读哈希集_observators=new HashSet();
受保护的void OnNext(int i)
{
foreach(var o in_观察员)
o、 OnNext(i);
}
受保护的无效单错误(例外e)
{
foreach(var o in_观察员)
o、 OnError(e);
}
已完成的受保护无效()
{
foreach(var o in_观察员)
o、 未完成();
}
公共void SendIntMessage(int i)
{
OnNext(i);
}
公共void EndStream()
{
未完成();
}
公共无效发送错误(异常e)
{
OnError(e);
}
公共IDisposable订阅(IObserver观察员)
{
_添加观察员(观察员);
返回GenericDisposable.Create(()=>_observators.Remove(observator));
}
}
这是一个长期运行的、热可观测的过程。它跟踪它的观察者,并且一次性取消他们的订阅

相比之下,考虑这一可观察到的情况:

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(() => {});
    }
}
公共类计数5:IObservable
{
公共IDisposable订阅(IObserver观察员)
{
OnNext观察员(1);
OnNext观察员(2);
OnNext观察员(3);
OnNext观察员(4);
OnNext观察员(5);
返回GenericDisposable.Create(()=>{});
}
}
这是一个立即运行的“冷”观察。没有办法中途退订:当你拿到一次性的时候,可观察的已经结束了


Disposable.Empty
DisposableCreate(()=>{})
的简单缩写。要向调用者返回有意义的
IDisposable
,您不应该在订阅期间同步生成所有通知。您应该在不同的上下文中异步生成它们,并立即将尚未完成的订阅返回给调用方。下面是一种方法,通过使用
任务。运行
方法调用
线程池上的通知

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);
    }
}
公共类MyObservable:ioobservable
{
公共IDisposable订阅(IObserver观察员)
{
var cts=新的CancellationTokenSource();
_=Task.Run(异步()=>
{
对于(int i=0;i<5;i++)
{
等待任务延迟(1000,cts.Token);
观察员OnNext(一);
}
observer.OnCompleted();
},cts.Token);
返回新的取消一次性(cts);
}
}
班级

表示具有关联的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); } }