Creating a weak subscription to an IObservable

前端 未结 6 1346
暗喜
暗喜 2021-02-01 05:05

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.

Say I have a control w

6条回答
  •  南笙
    南笙 (楼主)
    2021-02-01 05:43

    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 ToWeakObservable(this IObservable observable)
        {
            return Observable.Create(observer =>
                (IDisposable)new DisposableReference(new WeakObserver(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 : IObserver, IDisposable
    {
        private readonly WeakReference reference;
        private readonly IDisposable subscription;
        private bool disposed;
    
        public WeakObserver(IObservable observable, IObserver observer)
        {
            this.reference = new WeakReference(observer);
            this.subscription = observable.Subscribe(this);
        }
    
        public void OnCompleted()
        {
            var observer = (IObserver)this.reference.Target;
            if (observer != null) observer.OnCompleted();
            else this.Dispose();
        }
    
        public void OnError(Exception error)
        {
            var observer = (IObserver)this.reference.Target;
            if (observer != null) observer.OnError(error);
            else this.Dispose();
        }
    
        public void OnNext(T value)
        {
            var observer = (IObserver)this.reference.Target;
            if (observer != null) observer.OnNext(value);
            else this.Dispose();
        }
    
        public void Dispose()
        {
            if (!this.disposed)
            {
                this.disposed = true;
                this.subscription.Dispose();
            }
        }
    }
    

提交回复
热议问题