surpavan
surpavan

Reputation: 1422

Trying to understand IDisposable

I read some articles and blogs on Implementation if IDisposable and GC working set. However, I could not understand the core areas of differentiation like: Following is code of my test class:

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

My Test scenarios are as follows: 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

result of test1 is that GC is called immediately and I loose access to resources, I get null message.

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

Result is Dispose is never called, even for z in forloop, I dont understand this, why is z not disposed, is it waiting because the list has reference to its values?

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

Result: Test2 vs test3 is calling the dispose manually after adding to the list. Result is that I lost access to resource, I get null message. Why did this happen although I added the object to list before calling the dispose method.

Thank you.

Upvotes: 0

Views: 263

Answers (2)

Hans Passant
Hans Passant

Reputation: 942267

Unfortunately, the Dispose implementation that the Visual Basic IDE auto-generates is wrong in 99.9% of all cases. You should only use it if your class has a Finalize() method or the base class has a protected Dispose(Boolean) method. Which is extremely rare, finalizers are implemented by .NET Framework classes. It is their job to wrap unmanaged resources that should be released early.

It becomes 100% wrong when you find out that you can't write any meaningful code in the Dispose() method. Like this case, your class has no fields of a type that is disposable. Setting a field to Nothing has no effect.

Upvotes: 1

Andrew Morton
Andrew Morton

Reputation: 25057

You are adding a reference to the instance z which you create. When that instance is destroyed, the reference is no longer pointing to anything. The Using construct automatically calls Dispose for you. You can make a new copy of the object z by adding a method to the class:

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

and use list1.Add(z.Clone).

See Object.MemberwiseClone Method for more information and if you need to create a deep copy.

Upvotes: 0

Related Questions