[英]Reactive Observable Subscription Disposal
If I have access to an IObservable that I know is only ever going to return one item, will this work and is it the best usage pattern? 如果我可以访问我知道只会返回一个项目的IObservable,这是否有效并且它是最好的使用模式?
IDisposable disposable = null;
disposable = myObservable.Subscribe(x =>
{
DoThingWithItem(x);
if (disposable != null)
{
disposable.Dispose();
}
});
The disposable returned by the Subscribe
extension methods is returned solely to allow you to manually unsubscribe from the observable before the observable naturally ends. Subscribe
扩展方法返回的一次性返回仅允许您在观察结果自然结束之前手动取消订阅可观察对象。
If the observable completes - with either OnCompleted
or OnError
- then the subscription is already disposed for you. 如果observable完成 - 使用
OnCompleted
或OnError
- 那么订阅已经为您处理。
Try this code: 试试这段代码:
var xs = Observable.Create<int>(o =>
{
var d = Observable.Return(1).Subscribe(o);
return Disposable.Create(() =>
{
Console.WriteLine("Disposed!");
d.Dispose();
});
});
var subscription = xs.Subscribe(x => Console.WriteLine(x));
If you run the above you'll see that "Disposed!" 如果你运行上面的程序,你会看到“Disposed!” is written to the console when the observable completes without you needing call
.Dispose()
on the subscription. 当observable完成而不需要调用
.Dispose()
时,会写入控制台。
One important thing to note: the garbage collector never calls .Dispose()
on observable subscriptions, so you must dispose of your subscriptions if they have not (or may not have) naturally ended before your subscription goes out of scope. 需要注意的一件重要事情是:垃圾收集器永远不会在可观察的订阅上调用
.Dispose()
,因此如果订阅在订阅超出范围之前没有(或可能没有)自然结束,则必须处置它们。
Take this, for example: 以此为例,例如:
var wc = new WebClient();
var ds = Observable
.FromEventPattern<
DownloadStringCompletedEventHandler,
DownloadStringCompletedEventArgs>(
h => wc.DownloadStringCompleted += h,
h => wc.DownloadStringCompleted -= h);
var subscription =
ds.Subscribe(d =>
Console.WriteLine(d.EventArgs.Result));
The ds
observable will only attach to the event handler when it has a subscription and will only detach when the observable completes or the subscription is disposed of. ds
observable仅在具有订阅时附加到事件处理程序,并且仅在observable完成或处理订阅时才分离。 Since it is an event handler the observable will never complete because it is waiting for more events, and hence disposing is the only way to detach from the event (for the above example). 因为它是一个事件处理程序,所以observable永远不会完成,因为它正在等待更多事件,因此处理是从事件中分离的唯一方法(对于上面的例子)。
When you have a FromEventPattern
observable that you know will only ever return one value then it is wise to add the .Take(1)
extension method before subscribing to allow the event handler to automatically detach and then you don't need to manually dispose of the subscription. 如果你有一个
FromEventPattern
observable,你知道它只返回一个值,那么在订阅允许事件处理程序自动分离之前添加.Take(1)
扩展方法是明智的,然后你不需要手动处理订阅。
Like so: 像这样:
var ds = Observable
.FromEventPattern<
DownloadStringCompletedEventHandler,
DownloadStringCompletedEventArgs>(
h => wc.DownloadStringCompleted += h,
h => wc.DownloadStringCompleted -= h)
.Take(1);
I hope this helps. 我希望这有帮助。
Disclaimer: I'm also still learning Rx. 免责声明:我还在学习Rx。 So I'm not really an expert but I believe the disposable returned by
Subscribe
will only unsubscribe the subscription. 所以我不是真正的专家,但我相信
Subscribe
返回的一次性只会取消订阅订阅。 Also if the source completes, like in your case, the unsubscription is done automatically. 此外,如果源完成,就像您的情况一样,取消订阅会自动完成。 So I think the
Dispose
there is redundant and can be safely removed. 所以我认为
Dispose
存在冗余,可以安全地删除。
See the answer to this question for more info. 有关详细信息,请参阅此问题的答案。
The Take
function will do exactly what you are looking for. Take
功能将完全符合您的要求。 In this case, Take(1)
. 在这种情况下,
Take(1)
。
In contrast to some comments it's not at all uncommon to dispose of a subscription from inside OnNext
. 与一些评论相反,从
OnNext
内部处理订阅并不罕见。
While it's true that disposal at OnCompleted
and OnError
are done for you by a wrapped subscription that the Subscribe
extension method creates, you may want to unsubscribe based on a value you're observing (like in your case: the 1st one). 虽然
OnCompleted
和OnError
处理是通过Subscribe
扩展方法创建的包装订阅为您完成的,但您可能希望根据您正在观察的值取消订阅(例如在您的情况下:第一个)。 You don't always have an observable that is known to produce only one value. 您并不总是有一个已知只生成一个值的observable。
Problem is that you get the IDisposable
only after you have subscribed. 问题是您只有在订阅后才能获得
IDisposable
。 An observable may call you back on OnNext
even before it returns you the IDisposable
to unsubscribe (depending on things like the IScheduler
it uses). 即使在它返回
IDisposable
取消订阅之前,一个observable也可能会回拨OnNext
(取决于它使用的IScheduler
之类的东西)。
The System.Reactive.Disposables.SingleAssignmentDisposable
comes in handy in this case. 在这种情况下,
System.Reactive.Disposables.SingleAssignmentDisposable
派上用场。 It wraps an IDisposable
that you may assign late, and will immediately dispose it on assignment if the SingleAssignmentDisposable
already has been disposed by then. 它包装了一个你可以分配较晚的
IDisposable
,如果SingleAssignmentDisposable
已经处理了SingleAssignmentDisposable
,它将立即处理它。 Also it carries a property IsDisposed
which initially is false
and is set to true
when Dispose()
is called. 它还带有一个属性
IsDisposed
,它最初为false
并在调用Dispose()
时设置为true
。
So: 所以:
IObservable<string> source = ...;
var subscription = new SingleAssignmentDisposable();
subscription.Disposable = source.Subscribe(x =>
{
if (subscription.IsDisposed) // getting notified though I've told it to stop
return;
DoThingsWithItem(x);
if (x == "the last item I'm interested in")
subscription.Dispose();
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.