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
The key is to recognize that you are going to have to pass in both the target and a two-parameter action. A one-parameter action will never do it, because either you use a weak reference to your action (and the action gets GC'd), or you use a strong reference to your action, which in turn has a strong reference to the target, so the target can't get GC'd. Keeping that in mind, the following works:
using System;
namespace Closures {
public static class WeakReferenceExtensions {
/// returns null if target is not available. Safe to call, even if the reference is null.
public static TTarget TryGetTarget(this WeakReference reference) where TTarget : class {
TTarget r = null;
if (reference != null) {
reference.TryGetTarget(out r);
}
return r;
}
}
public static class ObservableExtensions {
public static IDisposable WeakSubscribe(this IObservable source, T target, Action action)
where T : class {
var weakRef = new WeakReference(target);
var r = source.Subscribe(u => {
var t = weakRef.TryGetTarget();
if (t != null) {
action(t, u);
}
});
return r;
}
}
}
Sample Observable:
using System;
using System.Reactive.Subjects;
namespace Closures {
public class Observable {
public IObservable ObservableProperty => _subject;
private Subject _subject = new Subject();
private int n;
public void Fire() {
_subject.OnNext(n++);
}
}
}
Usage:
Class SomeClass {
IDisposable disposable;
public void SomeMethod(Observable observeMe) {
disposable = observeMe.ObservableProperty.WeakSubscribe(this, (wo, n) => wo.Log(n));
}
public void Log(int n) {
System.Diagnostics.Debug.WriteLine("log "+n);
}
}