繁体   English   中英

我是否需要担心 Rx.NET FromEventPattern 会导致 memory 泄漏?

[英]Do I have to worry about memory leaks with Rx.NET FromEventPattern?

在 .NET 中,我基本上被提升为永远不会忘记取消订阅事件。 在 MVVM 应用程序中,我经常得到的就是这种结构。

public class WindowVm
{
    public EntityModel MyModel { get; set; }

    void Subscribe()
    {
        MyModel.PropertyChanged += DoSomething;
    }

    void Unsubscribe()
    {
        MyModel.PropertyChanged -= DoSomething;
    }
}

我需要取消订阅,因为如果我不取消订阅,MyModel 会保留对 WindowVm 的引用,并且只要 MyModel 存在,它就会一直保持活动状态。

我刚刚发现了反应式扩展,但我不知道我是否还需要考虑这个。 我找不到任何这样说的地方,但我也没有听到“哦,顺便说一句,它解决了那个烦人的事件取消订阅问题”,这将是一个致命的论点。

public class WindowVm
{
    public EntityModel MyModel { get; set; }

    void Subscribe()
    {
        MyModel.PropChangedObservable.Subscribe(e => DoSomething(e.Sender, e.EventArgs));
    }
}
public class EntityModel : ObservableBase
{
    public IObservable<EventPattern<PropertyChangedEventArgs>> PropChangedObservable { get; private set; }

    public EntityModel()
    {
        PropChangedObservable = Observable
               .FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
                   x => this.PropertyChanged += x,
                   x => this.PropertyChanged -= x);
    }
}

我不知道这是否会产生额外的参考。 那么这种方式呢?

public class WindowVm
{
    public EntityModel MyModel { get; set; }

    void Subscribe()
    {
        Observable
               .FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
                   x => MyModel.PropertyChanged += x,
                   x => MyModel.PropertyChanged -= x)
               .Subscribe(e => DoSomething(e.Sender, e.EventArgs));
    }
}

我没有使用 RX,但您使用的订阅方法返回一个 IDisposable,然后消费者应该使用它来取消订阅。 你的方法:

void Subscribe()
{    
    MyModel.PropChangedObservable.Subscribe(e => DoSomething(e.Sender, e.EventArgs));
}

那么应该是:

IDisposable Subscribe()
{    
    return MyModel.PropChangedObservable.Subscribe(e => DoSomething(e.Sender, e.EventArgs));
}

注意:我猜您的代码不是 100% 完整的,因为您缺少要在Subscribe上调用的方法,并且您已经硬编码DoSomething ,而我忽略了那部分

因此,您的 model 的观察者将首先调用 subscribe 并获取对 IDisposable 的引用。 一旦观察者完成,它应该在该引用上调用Dispose

回答你的问题

我不知道我是否还需要考虑这个

答案是肯定的,你仍然需要考虑这一点。 然而 RX 确实有自动取消订阅,但你需要知道你想听多少事件。 检查这个 SO question的答案。

我在 WinForms 中使用这种方法,它也适用于 WPF。 不幸的是,它会更改生成的代码,但是当您在设计器中更改内容时,VS 不会替换它。

public MainForm()
{
    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.

}

打开 InitializeComponent 方法并在设计器文件中更改 dispose 方法。

    'UserControl overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing AndAlso components IsNot Nothing Then
            OnDisposing() // <-- Add this line
            components.Dispose()
        End If
        MyBase.Dispose(disposing)
    End Sub

在ctor下实现OnDispose(我一般放在Load之前)

public void OnDisposing()
{
    var context = // TODO: get VM for current frm;
    if (context != null)
        context.Dispose(); // call dispose on VM.
}

然后,您的 VM 应取消订阅 Dispose 方法,该方法将在释放 UC 时调用(或稍后:D)。 这对于对话框等来说可以正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM