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メッセージが表示されます。

Test2:

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が破棄されないのですか、リストにその値への参照があるため、待機していますか?

Test3:

    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とtest3は、リストに追加した後、手動でdisposeを呼び出しています。その結果、リソースにアクセスできなくなり、nullメッセージが表示されます。disposeメソッドを呼び出す前にオブジェクトをリストに追加したのに、なぜこれが発生したのですか。

ありがとうございました。

4

2 に答える 2

1

残念ながら、Visual Basic IDEが自動生成するDisposeの実装は、すべてのケースの99.9%で間違っています。クラスにFinalize()メソッドがある場合、または基本クラスに保護されたDispose(Boolean)メソッドがある場合にのみ使用してください。これは非常にまれですが、ファイナライザーは.NETFrameworkクラスによって実装されます。早期にリリースする必要がある管理されていないリソースをラップするのが彼らの仕事です。

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 に答える