1

当我实现 IDisposable 时,VS 会自动生成这些区域化过程:

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

    ' IDisposable
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.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
        Me.disposedValue = True
    End Sub

    ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
    'Protected Overrides Sub Finalize()
    '    ' Do not change this code.  Put cleanup code in Dispose(ByVal 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)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

想象一下,我的班级有一个永远不会关闭/处置的一次性对象(来自 Process Class 的新流程),所以我想处置它在 Class 上实现 IDisposable ...

我的问题是:

  • 在上面代码的哪一行我需要放一个myProcess.Dispose()

  • 我有一些StringInteger变量不是一次性的,例如dim myVar as string = "value",如果我在处置一次性对象时将这些 vars 的值设置为空值会更好吗?像这样的东西?:

    sub dispose()
      myProcess.Dispose()
      myvar = nothing
    end sub
    
  • 我的类调用了一些 WinAPI 函数并且还覆盖了 WndProc 子来解析消息,我需要使用终结器或者我可以使用 SuppressFinalize?,如果我需要使用终结器......我需要做什么?只是我取消注释 Finalize 子,仅此而已?我不确定终结器的用途或何时以及如何使用它。


虽然我不确切知道实现 Dispose 方法的正确方法,但我正在以这种方式处理它,但肯定以一种或其他方式完全错误......:

#Region " Dispose "

    ''' <summary>
    ''' Disposes all the objects created by this class.
    ''' </summary>
    Public Sub Dispose() _
    Implements IDisposable.Dispose

        ' Process
        p.Dispose() 

        ' Public Properties
        Me.mp3val_location = Nothing
        Me.CheckFileExist = Nothing

        ' String variables
        StandardError = Nothing
        StandardOutput = Nothing
        Info = Nothing
        Warnings = Nothing
        Errors = Nothing
        Tags = Nothing

        ' RegEx variables
        Info_RegEx = Nothing
        Warning_RegEx = Nothing
        Fixed_RegEx = Nothing

        ' EventArgs Variables
        StartedArgs = Nothing
        ExitedArgs = Nothing

        GC.SuppressFinalize(Me)

    End Sub

#End Region

更新

所以...简化令人困惑的 VS 生成的代码,使其对我的要求更加直观和友好,我应该像这样使用它吗?:

Public Class Test : Implements IDisposable

Public Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
End Sub

Protected Overridable Sub Dispose(IsDisposing As Boolean)

    Static IsBusy As Boolean ' To detect redundant calls.

    If Not IsBusy AndAlso IsDisposing Then

        ' Dispose processes here...
        ' myProcess.Dispose()

    End If

    IsBusy = True

End Sub

End Class
4

1 回答 1

1

在上面代码的哪一行我需要放一个 myProcess.Dispose()

没有任何。你没有。您应该做的是创建类的任何实例作为using块的一部分。这将Dispose()在适当的时间自动调用。如果做不到这一点,请始终将您的类创建为块的一部分,并将其作为块的一部分try调用。Dispose()finally

如果我在处置一次性对象时将这些变量的值设置为空值会更好吗?

不,没有必要这样做。String 和 int 变量仅使用内存,垃圾收集器正确处理这些变量,而无需任何额外工作。

我的类调用了一些 WinAPI 函数并且还覆盖了 WndProc 子来解析消息,我需要使用终结器或者我可以使用 SuppressFinalize?,如果我需要使用终结器......我需要做什么 [do] 我需要做什么?

如果您的 WinAPI 调用分配了任何系统资源,例如文件句柄、gdi 句柄、线程、套接字等,并且如果这不是为您释放这些资源的现有 .Net 类的一部分,则您需要一个终结器。如果这两个条件都为真,您只需要一个终结器。很多时候,终结器只会调用该.Dispose(False)方法,如注释示例中所示,因此您的清理代码只需要存在于一个地方。

因此,在实现 IDisposable 时,大多数时候您只需要关注该示例中的第一个方法。您可能还想取消注释 Finalize() 方法,仅此而已。现在让我们看看那个方法:

' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
    If Not Me.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
    Me.disposedValue = True
End Sub

这里的诀窍是 TODO 评论令人困惑……甚至是误导。第一条评论(“dispose managed state”)是完全没有价值的,因为你永远不能自己dispose managed state。这完全取决于垃圾收集器。考虑到这一点,您可以完全删除 if 条件。我发现此规则的唯一例外是事件处理程序。您可以使用此位置取消订阅您班级中的任何代表。

第二个 TODO 注释(“免费的非托管资源”)更有用。它告诉您将非托管资源的清理代码放在哪里。它只是持续太久。如果它在第一句之后停止,那就更清楚了。如果您的类本身包装了任何 IDisposable 类的实例,那么这是为对象调用 .Dipose() 的好地方。

第三条 TODO 注释(“将大字段设置为空”)在很大程度上也是不必要的。在 .Net 中将项目设置为 NULL 通常对您没有帮助。在这种情况下,您已经在处置对象。这意味着无论如何它很可能会超出范围,并且这些对象在下次 GC 运行时仍然有资格被收集。这样做的唯一原因是如果您怀疑您的对象在处理后不会很快超出范围。在这种情况下,将这些字段设置为 null 可能会允许更快地收集那些较大的内存块......但这种情况将是您班级用户设计不佳的症状。

于 2013-11-10T22:34:41.417 回答