0

如果 IDisposable 和 GC 工作集,我阅读了一些关于实现的文章和博客。但是,我无法理解差异化的核心领域,例如:以下是我的测试类的代码:

Imports System.ComponentModel
Namespace Classes
    Public Class BaseClass
        Implements INotifyPropertyChanged
        Implements IDisposable

        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

        Protected Friend Sub NotifyPropertyChanged(ByVal info As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
        End Sub

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

        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' TODO: dispose managed state (managed objects).
                End If
            End If
            Me.disposedValue = True
        End Sub
        Public Sub Dispose() Implements IDisposable.Dispose
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class

    Public Class GenreClass
        Inherits BaseClass
#Region "Private Variables"
        Private _GenreValue As String
        Private _IconValue As String
        Private _IsSelectedValue As Boolean
        Private _IsExpandedValue As Boolean
#End Region

#Region "Property Variables"
        Property Genre As String
            Get
                Return _GenreValue
            End Get
            Set(Value As String)
                If Not _GenreValue = Value Then
                    _GenreValue = Value
                    NotifyPropertyChanged("Genre")
                End If
            End Set
        End Property
        Property Icon As String
            Get
                Return _IconValue
            End Get
            Set(Value As String)
                If Not _IconValue = Value Then
                    _IconValue = Value
                    NotifyPropertyChanged("Icon")
                End If
            End Set
        End Property
        Property IsSelected As Boolean
            Get
                Return _IsSelectedValue
            End Get
            Set(Value As Boolean)
                If Not _IsSelectedValue = Value Then
                    _IsSelectedValue = Value
                    NotifyPropertyChanged("IsSelected")
                End If
            End Set
        End Property
        Property IsExpanded As Boolean
            Get
                Return _IsExpandedValue
            End Get
            Set(Value As Boolean)
                If Not _IsExpandedValue = Value Then
                    _IsExpandedValue = Value
                    NotifyPropertyChanged("IsExpanded")
                End If
            End Set
        End Property
#End Region

        Protected Overrides Sub Dispose(disposing As Boolean)
            Genre = Nothing
            MyBase.Dispose(disposing)
        End Sub

        Public Overrides Function ToString() As String
            Return Genre
        End Function            
    End Class
End Namespace

我的测试场景如下: Test1:

Dim list1 As New List(Of HODLib.Classes.GenreClass)
For i = 0 To 4
    Using z As New HODLib.Classes.GenreClass

        With z
            .Genre = "asdasd"
            .Icon = "asdasdasdasdasd"
            .IsExpanded = True
            .IsSelected = True

        End With
        list1.Add(z)

    End Using
Next
For Each z In list1
    MessageBox.Show(z.ToString)
Next

test1 的结果是立即调用 GC 并且我失去了对资源的访问权限,我收到 null 消息。

测试2:

Dim list1 As New List(Of HODLib.Classes.GenreClass)
For i = 0 To 4

    Dim z As New HODLib.Classes.GenreClass
    With z
        .Genre = "asdasd"
        .Icon = "asdasdasdasdasd"
        .IsExpanded = True
        .IsSelected = True

    End With
    list1.Add(z)

Next
For Each z In list1
    MessageBox.Show(z.ToString)
Next

结果是从未调用过 Dispose,即使对于 forloop 中的 z,我也不明白,为什么 z 没有被释放,是因为列表引用了它的值而等待吗?

测试3:

    Dim list1 As New List(Of HODLib.Classes.GenreClass)
        For i = 0 To 4

            Dim z As New HODLib.Classes.GenreClass
            With z
                .Genre = "asdasd"
                .Icon = "asdasdasdasdasd"
                .IsExpanded = True
                .IsSelected = True

            End With
            list1.Add(z)
            z.Dispose()

        Next
        For Each z In list1
            MessageBox.Show(z.ToString)
        Next

结果:Test2 vs test3 在添加到列表后手动调用 dispose。结果是我失去了对资源的访问权限,我收到了空消息。为什么会发生这种情况,尽管我在调用 dispose 方法之前将对象添加到列表中。

谢谢你。

4

2 回答 2

1

不幸的是,Visual Basic IDE 自动生成的 Dispose 实现在 99.9% 的情况下都是错误的。仅当您的类具有 Finalize() 方法或基类具有受保护的 Dispose(Boolean) 方法时,才应使用它。这是极其罕见的,终结器是由 .NET Framework 类实现的。他们的工作是包装应该提前释放的非托管资源。

当您发现无法在 Dispose() 方法中编写任何有意义的代码时,它就会 100% 出错。像这种情况下,您的类没有一次性类型的字段。将字段设置为 Nothing 无效。

于 2012-09-02T18:33:49.117 回答
0

您正在添加对您创建的实例 z 的引用。当该实例被销毁时,引用不再指向任何东西。该Using构造会自动为您调用 Dispose。您可以通过向类添加方法来制作对象 z 的新副本:

Public Function Clone() As GenreClass
    Return DirectCast(Me.MemberwiseClone(), GenreClass)
End Function

并使用list1.Add(z.Clone).

有关详细信息以及是否需要创建深层副本,请参阅Object.MemberwiseClone 方法。

于 2012-09-02T18:06:56.203 回答