[英]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.