我的 ViewModel 实际上被处理掉了吗

Is my ViewModel actually being disposed of

我正在尝试了解在 mvvm 环境中正确处理视图和视图模型。我在停靠环境中遇到了一个关于各种用户控件(本质上是我的视图)及其相关视图模型的特定问题(类似于您可能在 visual studio 中看到的那种东西)。

我在这里阅读了无数的帖子、博客和问题,终于找到了一些我认为有用的东西(确实可能有用,但我只是不明白这个过程)。

在我的视图模型中,我实现了 Idiposable,在视图(它被设置为它的数据上下文)中,我确保视图在卸载时调用它的数据上下文。因此视图关闭并在其数据上下文(我的视图模型)上调用 dispose 以确保我可以清理任何可能挂起并导致内存泄漏(如事件处理程序)的遗留物。

一个这样的视图模型在覆盖的处置子中具有以下代码:

   ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            ' 

            ' 
            If mwvm.CanCallDisposeOnErsSubmissionViewModel Then
                mwvm = Nothing
                subEd = Nothing
                retEd = Nothing
            End If

            ' TODO: set large fields to null.
        End If
        Try

            If Not mwvm.CanCallDisposeOnErsSubmissionViewModel Then
                disposedValue = False
            End If
        Catch ex As NullReferenceException
            disposedValue = True
        End Try
        MessageBox.Show("DisposeValue = " & disposedValue.tostring)
    End Sub

此视图模型引用了应用程序主视图模型中的元素(我认为在使用后清理它很重要的原因之一。但是,如果最终用户要么重新绘制作为数据上下文的视图在其所在的停靠站点中添加或关闭其他 windows(因此需要条件语句)。

现在这可能并不优雅,而且很可能不是正确的方法,但我的问题来自观察以下内容。

当我选择主动关闭视图并且条件语句允许进行清理并将处置值设置为 true 时,我会认为这意味着视图模型已经很好地真正关闭了并处理掉,但是我可以让程序继续 运行 嘿,突然弹出一个消息框,它只能来自上面的处理程序。那么我的模型是否被正确处理,这是正常行为(大概是垃圾收集器正在做它的事情所以它可以被忽略)还是我的某个地方存在基本错误?

使用一次性模式时,您必须在 Dispose() 中调用 GC.SuppressFinalize(this) 以阻止 GC 在完成对象时调用 Dispose() 方法(因为您无法控制关于 GC 何时执行)

来自 Disposable Pattern 上的 MSDN:

public class DisposableResourceHolder : IDisposable {

    private SafeHandle resource; // handle to a resource

    public DisposableResourceHolder(){
        this.resource = ... // allocates the resource
    }

    public void Dispose(){
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing){
        if (disposing){
            if (resource!= null) resource.Dispose();
        }
    }
}

补充 Tseng 已经说过的话,但特别针对 VB。

如果您在 VB 中的 class 上实施 IDisposable,以下样板代码将添加到 class:

#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls

' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
    If Not disposedValue Then
        If disposing Then
            ' TODO: dispose managed state (managed objects).
        End If

        ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
        ' TODO: set large fields to null.
    End If
    disposedValue = True
End Sub

' TODO: override Finalize() only if Dispose(disposing As Boolean) above has code to free unmanaged resources.
'Protected Overrides Sub Finalize()
'    ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
'    Dispose(False)
'    MyBase.Finalize()
'End Sub

' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
    ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
    Dispose(True)
    ' TODO: uncomment the following line if Finalize() is overridden above.
    ' GC.SuppressFinalize(Me)
End Sub

Whosebug 实际上以比 visual studio 编辑器更易读的方式突出显示代码。我已经将我知道需要处理的位添加到 Overridable Sub Dispose。我已经注意到该部分中取消注释 Ovveride Finalize 部分的评论。我错过的是继续并取消注释实际 Dispose 方法中的 GC.SuppressFinalize(Me) 行。我犯了一个愚蠢的错误,我唯一可以提供的借口是绿色评论将事物融合得太好了。

希望这对其他人有所帮助。