簡體   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