简体   繁体   English

反应性可观察认购出售事项

[英]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完成 - 使用OnCompletedOnError - 那么订阅已经为您处理。

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). 虽然OnCompletedOnError处理是通过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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM