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