简体   繁体   English

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

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

In .NET I've been essentially raised to never ever forget to unsubscribe to events.在 .NET 中,我基本上被提升为永远不会忘记取消订阅事件。 In MVVM apps what I often end up with is this construct.在 MVVM 应用程序中,我经常得到的就是这种结构。

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

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

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

I need to unsubscribe, because if I don't MyModel would keep a reference to the WindowVm and keep it alive for as long as MyModel lives.我需要取消订阅,因为如果我不取消订阅,MyModel 会保留对 WindowVm 的引用,并且只要 MyModel 存在,它就会一直保持活动状态。

I just found out about reactive extensions, but I can't find out whether I need to still think about this.我刚刚发现了反应式扩展,但我不知道我是否还需要考虑这个。 I cant find anywhere that says so, but I also don't hear "oh and btw it solves that annoying event unsubscribe problem" which would be a killer argument.我找不到任何这样说的地方,但我也没有听到“哦,顺便说一句,它解决了那个烦人的事件取消订阅问题”,这将是一个致命的论点。

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);
    }
}

I can't tell whether this would create an extra reference.我不知道这是否会产生额外的参考。 And what about this way?那么这种方式呢?

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));
    }
}

I have not worked with RX but the Subscribe method that you are using is returning an IDisposable which should then be used by the consumer to unsubscribe.我没有使用 RX,但您使用的订阅方法返回一个 IDisposable,然后消费者应该使用它来取消订阅。 Your method:你的方法:

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

Should then be:那么应该是:

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

Note: I'm guessing your code is not 100% complete as you are missing the method to be invoked on Subscribe and you have hard-coded DoSomething and I'm ignoring that part注意:我猜您的代码不是 100% 完整的,因为您缺少要在Subscribe上调用的方法,并且您已经硬编码DoSomething ,而我忽略了那部分

So the observer of your model would first call subscribe and acquire the reference to IDisposable.因此,您的 model 的观察者将首先调用 subscribe 并获取对 IDisposable 的引用。 Once the observer is finished then it should call Dispose on that reference.一旦观察者完成,它应该在该引用上调用Dispose

To answer your question回答你的问题

I can't find out whether I need to still think about this我不知道我是否还需要考虑这个

The answer is yes, you still need to think about this.答案是肯定的,你仍然需要考虑这一点。 However the RX does have automatic unsubscription but you need to know how many events you want to listen to.然而 RX 确实有自动取消订阅,但你需要知道你想听多少事件。 Check the answer of this SO question .检查这个 SO question的答案。

I am using this approach in WinForms and it will also work for WPF.我在 WinForms 中使用这种方法,它也适用于 WPF。 Unfortunately, it changes the generated code, but VS won't replace it when you change things in designer.不幸的是,它会更改生成的代码,但是当您在设计器中更改内容时,VS 不会替换它。

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

    ' Add any initialization after the InitializeComponent() call.

}

Open InitializeComponent method and in designer file change dispose method.打开 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

Implement OnDispose under the ctor (I usually place it before Load)在ctor下实现OnDispose(我一般放在Load之前)

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

Your VM should then unsubscribe in on Dispose method that will be called when UC is disposed (or later:D ).然后,您的 VM 应取消订阅 Dispose 方法,该方法将在释放 UC 时调用(或稍后:D)。 That will work OK for dialogs etc.这对于对话框等来说可以正常工作。

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

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