当没有显式调用观察者上的Dispose时,我对ObservableForProperty生命周期的生命感到好奇。在这种情况下,我不太在意订阅太长等问题。

在传统的.NET中,如果您有事件,除非您取消订阅,否则可能会导致内存泄漏,原因是对象的生存期已绑定(bind)到该事件。例如,按照http://msdn.microsoft.com/en-us/magazine/cc163316.aspx的建议:

事件也可以是强大的根引用,因此可以促成强大的引用路径,从而影响对象的生存期。公共(public)语言运行时(CLR)2.0中的普通事件是事件源和监听器之间的双向强引用,因此可以使对象(源或监听器)保持事件状态,否则该对象应该已经失效。

在遇到INotifyPropertyChanged对象时浏览ReactiveUI代码库,我注意到您正在使用FromEventPattern订阅INotifyPropertyChange事件。

通过创建强引用路径,使用ObservableForProperty是否可以解决使对象保持更长时间事件的问题?

谢谢,
格伦

最佳答案

您是正确的,如果使用不当,错误地使用WhenAny/ObservableForProperty可能会导致应用程序泄漏内存。考虑以下代码:

public ItemInAListBoxViewModel(MainWindowViewModel mainWindow)
{
    this.window = mainWindow;

    // Reset the "selected" when the user minimizes
    this.WhenAnyValue(x => x.window.IsMinimized)
        .Where(x => x == true)
        .Subscribe(x => this.IsSelected = false);
}

因为我们已经完成了一个对象,该对象的生命周期比我们的生命周期(即ListBox项与Window的)长,所以我们将永久持有ListBox项,直到Window消失(在您的应用程序中可能永远不会出现)。

如果仅对自己的对象使用WhenAny(即始终为this.WhenAny,从不someObject.WhenAny),则可以避免绝大多数情况。

有关依赖项属性的特别说明

无论如何,您都有来处理通过DependencyProperty的任何WhenAny,否则您将泄漏。因为Windows。

废话,我现在该怎么办?

ReactiveUI中添加了一个新功能来处理您确实要执行此操作的场景,称为“激活”。您可以在以下位置找到更多信息:
  • The release notes for RxUI 5.5
  • The PR that added this feature

  • 现在,我们可以定义“仅在屏幕上才可事件的事物”的作用域,该作用域在将View及其ViewModel从屏幕上移除(即从WPF中的Visual Tree中移除)后将立即消失。
    public ItemInAListBoxViewModel(MainWindowViewModel mainWindow)
    {
        this.window = mainWindow;
    
        Activator = new ViewModelActivator();
    
        // This gets called every time the View for this VM gets put on screen
        this.WhenActivated(d => {
            // The 'd' is for "Dispose this when you're Deactivated"
            d(this.WhenAnyValue(x => x.window.IsMinimized)
                .Where(x => x == true)
                .Subscribe(x => this.IsSelected = false));
        });
    }
    

    为了使此工作有效,这是必须满足的条件:
  • 您的VieWModel需要实现ISupportsActivation( super 简单)
  • 与您的ViewModel关联的View也需要调用WhenActivated

  • 听起来很难!

    看起来像那样,但事实并非如此。只要记住两件事:
  • 不要通过任何永久存在的对象,除非您也永久存在
  • 如果需要,请使用WhenActivated。
  • 09-25 15:23