实现IDisposable

时间:2013-11-10 22:09:01

标签: .net vb.net winforms dispose idisposable

当我实现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

想象一下,我的类有一个永远不会被关闭/处理的一次性对象(一个来自进程类的新进程),所以我想在类上实现IDisposable ... ...

我的问题是:

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

  • 我有一些字符串整数变量,这些变量不像例如dim myVar as string = "value"那样是一次性的,如果我改变这些变量的值,那就更好了当我丢弃一次性物品时,变为空值?这样的事情?:

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


虽然我不确切地知道实现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

1 个答案:

答案 0 :(得分:0)

  

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

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

  

当我丢弃一次性物品时,如果我将这些变量的值变为空值会更好吗?

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

  

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

如果你的WinAPI调用分配任何系统资源,例如文件句柄,gdi句柄,线程,套接字等, ,如果不是这样,你需要一个终结器作为现有.Net类的一部分,它将为您处理释放这些资源。如果这些条件的两个都是真的,您只需要一个终结器。通常,终结器只会调用' 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 方法,如注释示例所示,这样您的清理代码只需要在一个地方生效。

因此,在实现IDisposable时,大多数情况下您只需要关注该示例中的第一个方法。您可能还想取消注释Finalize()方法,但就是这样。现在让我们来看看这个方法:

{{1}}

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

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

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