创建对IObservable的弱订阅 [英] Creating a weak subscription to an IObservable

查看:73
本文介绍了创建对IObservable的弱订阅的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想做的是确保如果对观察者的唯一引用是可观察到的,则会收集到它的垃圾并停止接收消息.

What I want to do is ensure that if the only reference to my observer is the observable, it get's garbage collected and stops receiving messages.

说我有一个控件,上面有一个名为Messages的列表框,此代码位于后面:

Say I have a control with a list box on it called Messages and this code behind:

//Short lived display of messages (only while the user's viewing incoming messages)
public partial class MessageDisplay : UserControl
{
    public MessageDisplay()
    {
        InitializeComponent();
        MySource.IncomingMessages.Subscribe(m => Messages.Items.Add(m));
    }
}

正在连接到此源:

//Long lived location for message store
static class MySource
{
    public readonly static IObservable<string> IncomingMessages = new ReplaySubject<string>;
}

我不想要的是将消息显示不再可见后再保存在内存中.理想情况下,我想扩展一下,这样我就可以写:

What I don't want is to have the Message Display being kept in memory long after it's no longer visible. Ideally I'd like a little extension so I can write:

MySource.IncomingMessages.ToWeakObservable().Subscribe(m => Messages.Items.Add(m));

我也不想依赖于MessageDisplay是用户控件这一事实,因为我稍后将希望使用MessageDisplayViewModel进行MVVM设置,而该设置将不是用户控件.

I also don't want to rely on the fact that MessageDisplay is a user control as I will later want to go for an MVVM setup with MessageDisplayViewModel which won't be a user control.

推荐答案

以下代码受dtb的原始帖子启发.唯一的变化是它将IDisposable的一部分返回给观察者一个引用.这意味着只要保持对链末端的IDisposable的引用,对IObserver的引用将一直保持有效(假定所有一次性物品在其之前都保留了对一次性物品的引用).这允许使用诸如Subscribe(M=>DoSomethingWithM(M))之类的扩展方法,因为我们保留了对隐式构造的IObserver的引用,但没有对从源到IObserver的强烈引用(这会产生内存韭葱).

The code below is inspired by dtb's original post. The only change is that it returns a reference to the observer as part of the IDisposable. This means that the reference to the IObserver will be kept alive as long as you keep a reference to the IDisposable that you get out at the end of the chain (assuming all disposables keep a reference to the disposable before them). This allows the usage of the extension methods such as Subscribe(M=>DoSomethingWithM(M)) because we keep a reference to the implicitly constructed IObserver but we don't keep a strong reference from the source to the IObserver (which would produce a memory leek).

using System.Reactive.Linq;

static class WeakObservation
{
    public static IObservable<T> ToWeakObservable<T>(this IObservable<T> observable)
    {
        return Observable.Create<T>(observer =>
            (IDisposable)new DisposableReference(new WeakObserver<T>(observable, observer), observer)
            );
    }
}

class DisposableReference : IDisposable
{
    public DisposableReference(IDisposable InnerDisposable, object Reference)
    {
        this.InnerDisposable = InnerDisposable;
        this.Reference = Reference;
    }

    private IDisposable InnerDisposable;
    private object Reference;

    public void Dispose()
    {
        InnerDisposable.Dispose();
        Reference = null;
    }
}

class WeakObserver<T> : IObserver<T>, IDisposable
{
    private readonly WeakReference reference;
    private readonly IDisposable subscription;
    private bool disposed;

    public WeakObserver(IObservable<T> observable, IObserver<T> observer)
    {
        this.reference = new WeakReference(observer);
        this.subscription = observable.Subscribe(this);
    }

    public void OnCompleted()
    {
        var observer = (IObserver<T>)this.reference.Target;
        if (observer != null) observer.OnCompleted();
        else this.Dispose();
    }

    public void OnError(Exception error)
    {
        var observer = (IObserver<T>)this.reference.Target;
        if (observer != null) observer.OnError(error);
        else this.Dispose();
    }

    public void OnNext(T value)
    {
        var observer = (IObserver<T>)this.reference.Target;
        if (observer != null) observer.OnNext(value);
        else this.Dispose();
    }

    public void Dispose()
    {
        if (!this.disposed)
        {
            this.disposed = true;
            this.subscription.Dispose();
        }
    }
}

这篇关于创建对IObservable的弱订阅的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆