我对本书的发布商子论坛上的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时实际导致取消订阅,应该是什么方式?
我对Observable和Observer使用此内容进行了解析
我不得不介绍订阅处理程序
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:如果低估请在评论中加入理由,这样我就可以避免在提问时重复出错。
答案 0 :(得分:2)
我应该说清楚所有这些都是Rx设计内部的演示。你可以看一下班级AnonymousObservable<T>
,
AnonymousObserver<T>
和AnonymousDisposable
,这是框架的工作方式。挺直的。但是,您几乎不应该使用任何此类代码,而应使用Disposable.Create
和Observable.Create
之类的内容。如果您正在实施IObservable
,那么您几乎肯定做错了。
这里有一个基本思想:可观察者需要产生一个IDisposable
,它将相关的观察者从观察者的内部观察者名单中删除。您的代码(错误地)从内部列表中删除所有观察者。
这是一种基本的一次性产品,可以轻松创建功能。使用此代码,GenericDisposable.Create
与Disposable.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.Empty
是DisposableCreate(() => {})
的简单简写。
答案 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);
}
}
代表具有关联
CancellationToken
的一次性资源,该资源将在处置后设置为取消请求状态。