ReactiveUI是否泄漏订阅?

时间:2012-01-18 20:45:41

标签: system.reactive reactiveui

我已经从博客中查看了ReactiveUi的示例,我想知道ReactiveUI是否在下面有某种订阅管理工具,或者是忽略了他们可能泄漏订阅这一事实的例子?

每当我在ReactiveUi中调用一个导致IDisposable的方法时,我是否需要保留该引用并自行跟踪它?这也意味着我的ViewModel需要是一次性的,这似乎很难,因为我们不知道什么时候连接的“视图”消失了(即如果我的ViewModel反映了数据网格中的项目),所以似乎没有合适的叫做出售的地方。

3 个答案:

答案 0 :(得分:14)

您还必须记住,Rx和ReactiveUI返回的IDisposable与非托管内存无关 - 它只是简单的.NET对象,仍由垃圾收集器引用。

您在ReactiveObjects的构造函数中创建的大多数订阅都将绑定到宿主对象的生命周期 - 因此当它超出范围并受GC影响时,所有订阅也将如此,CLR将检测到循环引用,只是核实一切。

正如Enigmativity所提到的,一个棘手的问题是当您使用FromEventPattern将订阅的生命周期(可能是ViewModel)与WPF对象的生命周期联系起来时。但是,我认为如果你经常在ReactiveUI中使用FromEventPattern,那么你肯定是在做错了。

RxUI是关于ViewModels的,而ViewModels都是关于命令属性(以及如何相互关联属性),因此您可以测试<用户体验的行为与其视觉效果分开。

答案 1 :(得分:11)

如果您需要从观察中取消订阅早期,则只需要保留对订阅返回的IDisposable的引用。当观察者通过DisposeOnCompleted消息终止时,Observable会自然致电OnError

但是,当您拥有无限可观察订阅(即FromEventPattern)时,您确实需要保留引用,但这与在关闭表单/视图之前需要删除事件处理程序完全相同。

答案 2 :(得分:2)

为了安全起见,我将从现在开始使用这种模式。我可能会 通过扩展方法修改工作,但原则是合理的。确定你 不要泄漏您想要删除的订阅

class Mesh2D{

    public Mesh2D()
    {
        DisposeOnUnload(CreateBindings());
    }

    // Register all disposables for disposal on
    // UIElement.Unload event. This should be
    // moved to an extension method.
    void DisposeOnUnload(IEnumerable<IDisposable> disposables)
    {
        var d = new CompositeDisposable(disposables);
        var d2 = this.UnloadedObserver()
            .Subscribe(e => d.Dispose());
        var d3 = this.Dispatcher.ShutdownStartedObserver()
            .Subscribe(e => d.Dispose());
        d.Add(d2);
        d.Add(d3);
    }

    // Where your bindings are simply yielded and
    // they are removed on Unload magically
    IEnumerable<IDisposable> CreateBindings()
    {
        // When the size changes we need to update all the transforms on 
        // the markers to reposition them. 
        yield return this.SizeChangedObserver()
            .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
            .Subscribe(eventArgs => this.ResetImageSource());

        // If the points change or the viewport changes
        yield return this.WhenAny(t => t.Mesh, t => t.Viewport, (x, t) => x.Value)
            .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
            .Subscribe(t => this.UpdateMeshChanged());
    }
}

注意我正在自动生成包装RX FromEventPattern 扩展方法,所以我得到SizeChangedObserver()和UnloadedObserver() 免费而不是难以记住的FromEventPattern格式。

包装代码就是这样生成的

public static IObservable<EventPattern<RoutedEventArgs>> UnloadedObserver(this FrameworkElement This){
    return Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(h => This.Unloaded += h, h => This.Unloaded -= h);
}

上述模式可能用于取消绑定IDisposable 查看模型。