Implementation of IDisposable

[RTS]BN+VS*

Well-known member
Joined
Feb 3, 2009
Messages
53
Location
BELGIUM - East Flanders
Programming Experience
1-3
Hey,

I implemented IDisposable into one of my classes, but don't know if I did it correctly. Can someone tell me what will be cleared from memory and what will remain after calling .Dispose on an instance of this class?

VB.NET:
Option Strict On : Option Explicit On

Imports System.ComponentModel
Imports System.IO
Imports System.Net

Imports Bn
Imports Bn.Core

Namespace Bn.Classes

#Region " Public Class Updater "
    ''' <summary>Class for getting and downloading update info and update files</summary>
    ''' <remarks>Class Updater v1.0.2, by De Dauw Jeroen - March 2009</remarks>
    Public Class Updater
        Inherits System.Object
        Implements IDisposable
        Implements ICloneable

#Region "Nested types"

#Region " Public Class UpdateInfo "
        ''' <summary>Contains info about an update</summary>
        Public Class UpdateInfo
            Public updatePath, updateFile As String
            Public updateName, updateComments As String
            Public updateReleaseDate As Int32 = 0
            Public updateVersion As New Version
        End Class
#End Region

#Region " Public Class Version "
        ''' <summary>Contains version data and allows to compare two versions</summary>
        Public Class Version
            Public major, minor, build, revision As Int32

            Public Overloads Shared Operator >( _
            ByVal v1 As Version, ByVal v2 As Version) As Boolean
                If v1.major = v2.major Then
                    If v1.minor = v2.minor Then
                        If v1.build = v2.build Then
                            Return v1.revision > v2.revision
                        Else
                            Return v1.build > v2.build
                        End If
                    Else
                        Return v1.minor > v2.minor
                    End If
                Else
                    Return v1.major > v2.major
                End If
            End Operator

            Public Overloads Shared Operator <( _
            ByVal v1 As Version, ByVal v2 As Version) As Boolean
                Return v1 IsNot v2 And Not v1 > v2
            End Operator

            Public Sub New(Optional ByVal mjor As Int32 = 0, _
                   Optional ByVal mnor As Int32 = 0, _
                   Optional ByVal bld As Int32 = 0, _
                   Optional ByVal rev As Int32 = 0)
                major = mjor
                minor = mnor
                build = bld
                rev = revision
            End Sub
        End Class
#End Region

#End Region

#Region "Events"
        ''' <summary>Occurs when no internet connection is found when attempting to download a file with the updater</summary>
        Public Event NoConnectionFound As Delegates.EventHandler

        ''' <summary>Occurs when the updater starts to check for update information</summary>
        Public Event UpdateCheckStarted As Delegates.EventHandler
        ''' <summary>Occurs when the updater completed checking for update information</summary>
        Public Event UpdateCheckCompleted As Delegates.EventHandler
        ''' <summary>Occurs when the updater has successfully downloaded the update information</summary>
        Public Event UpdateInfoDownloaded As Delegates.EventHandler
        ''' <summary>Occurs when the updater can't find any update info</summary>
        Public Event NoUpdateInfoFound As Delegates.EventHandler

        ''' <summary>Occurs when the updater starts to download the update</summary>
        Public Event UpdateDownloadStarted As Delegates.EventHandler
        ''' <summary>Occurs when the updater completed attempting to downloading the update</summary>
        Public Event UpdateDownloadCompleted As Delegates.EventHandler
        ''' <summary>Occurs when the updater completed downloading the update</summary>
        Public Event UpdateFileDownloaded As Delegates.EventHandler
        ''' <summary>Occurs when the updater can't find the update file</summary>
        Public Event NoUpdateFileFound As Delegates.EventHandler

        ''' <summary>Occurs when the update process is started</summary>
        Public Event UpdateStarted As Delegates.EventHandler
        ''' <summary>Occurs when the update process is aborted</summary>
        Public Event UpdateAborted As Delegates.ErrorEventHandler

        ''' <summary>Occurs when the update info is changed</summary>
        Public Event InfoChanged As Delegates.EventHandler

        ''' <summary>Occurs when the startup path is changed</summary>
        Public Event StartupPathChanged As Delegates.EventHandler
        ''' <summary>Occurs when the application name is changed</summary>
        Public Event ApplicationNameChanged As Delegates.EventHandler
        ''' <summary>Occurs when the application version is changed</summary>
        Public Event ApplicationVersionChanged As Delegates.EventHandler
        ''' <summary>Occurs when the update path is changed</summary>
        Public Event UpdatePathChanged As Delegates.EventHandler
        ''' <summary>Occurs when the update file is changed</summary>
        Public Event UpdateFileChanged As Delegates.EventHandler
#End Region

#Region "Fields"
        ' The name for the updater that will be stored in the application folder
        Private Const autorunAppName As String = "updater.exe"

        ' Background workers and webclient
        Private WithEvents bgwUpdateInfoWorker, bgwUpdateFileWorker As New BackgroundWorker
        Private WithEvents webClient As New WebClient

        ' Info for the download of update info
        Private m_update_path, m_update_file As String
        Private m_new_path, m_new_file As String

        ' Application info
        Private m_statupPath As String
        Private m_appName As String = "Application"
        Private m_appVersion As New Version

        ' Holder for the recieved info
        Private m_contents As String
        Private m_info As New UpdateInfo

        ' Status info
        Private m_hasDownloaded As Boolean = False
        Private m_hasFoundConnection As Boolean = False
        Private m_isDisposed As Boolean = False
#End Region

#Region "Constructors"
        ''' <summary>Create a new instance</summary>
        Public Sub New()

        End Sub

        ''' <summary>Create a new instance</summary>
        Protected Sub New(ByVal info As UpdateInfo, ByVal startupPath As String, ByVal appName As String, _
                       ByVal appVersion As Version, ByVal updatePath As String, _
                       ByVal updateFile As String, ByVal contents As String, _
                       ByVal foundConnection As Boolean, ByVal hasDownloaded As Boolean)
            Me.Info = info
            Me.StartupPath = startupPath
            Me.ApplicationName = appName
            Me.ApplicationVersion = appVersion
            Me.UpdatePath = updatePath
            Me.UpdateFile = updateFile
            Me.Contents = contents
            m_hasFoundConnection = foundConnection
            m_hasDownloaded = hasDownloaded
        End Sub
#End Region

#Region "Public methods"
        ''' <summary>Set the application version according to a system.version object</summary>
        Public Sub SetVersion(ByVal version As System.Version)
            With Me.ApplicationVersion
                .major = version.Major
                .minor = version.Minor
                .build = version.Build
                .revision = version.Revision
            End With
        End Sub

        ''' <summary>Check if there are avaible updates</summary>
        Public Sub CheckForUpdates()
            m_hasFoundConnection = Utilities.InternetConnectionAvaible
            If m_hasFoundConnection Then
                bgwUpdateInfoWorker.RunWorkerAsync()
                RaiseEvent UpdateCheckStarted(Me, New EventArgs)
            Else
                RaiseEvent NoConnectionFound(Me, New EventArgs)
            End If
        End Sub

        ''' <summary>Download an updater</summary>
        Public Sub DownloadUpdate()
            m_hasFoundConnection = Utilities.InternetConnectionAvaible
            If m_hasFoundConnection Then
                m_hasDownloaded = True
                bgwUpdateFileWorker.RunWorkerAsync()
                RaiseEvent UpdateDownloadStarted(Me, New EventArgs)
            Else
                RaiseEvent NoConnectionFound(Me, New EventArgs)
            End If
        End Sub

        ''' <summary>Run a downloaded updater</summary>
        Public Sub RunUpdate()
            If Me.UpdaterDownloaded Then
                Try
                    System.Diagnostics.Process.Start(Me.UpdaterPath)
                    RaiseEvent UpdateStarted(Me, New EventArgs)
                Catch ex As Exception
                    RaiseEvent UpdateAborted(Me, New Core.ErrorEventArgs(ex.ToString))
                End Try
            Else
                RaiseEvent UpdateAborted(Me, New Core.ErrorEventArgs("The updater was not found on the correct location"))
            End If
        End Sub

        ''' <summary>Create a shallow copy of this instance</summary>
        Public Overridable Function ShallowClone() As Updater
            Return CType(Me.MemberwiseClone, Updater)
        End Function

        ''' <summary>Create a deep copy of this instance</summary>
        Public Overridable Function Clone() As Object _
        Implements System.ICloneable.Clone
            Clone = New Updater()
        End Function

        ''' <summary>Dispose the updaters recources</summary>
        Public Overridable Sub Dispose() _
        Implements IDisposable.Dispose
            Me.Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

#Region "Private/protected methods"
        ''' <summary>Attempt to download the update info and store it into the Me.Info object</summary>
        Protected Overridable Sub bgwUpdateInfoWorker_DoWork() Handles bgwUpdateInfoWorker.DoWork
            Me.Contents = ""
            Try
                Dim updateData(), versionData() As String
                Dim reader As New StreamReader((New WebClient).OpenRead(Me.UpdatePath & "/" & Me.UpdateFile))
                Me.Contents = reader.ReadToEnd
                reader.Close()
                updateData = Me.Contents.Split(Chr(10))
                versionData = updateData(0).Split("."c)
                With Me.Info
                    With .updateVersion
                        .major = CInt(versionData(0))
                        .minor = CInt(versionData(1))
                        .build = CInt(versionData(2))
                        .revision = CInt(versionData(3))
                    End With
                    .updateReleaseDate = CInt(updateData(1))
                    .updatePath = updateData(2)
                    .updateFile = updateData(3)
                    .updateName = updateData(4)
                    .updateComments = ""
                    For dataNr As Int32 = 5 To updateData.Length - 1
                        .updateComments &= updateData(dataNr) & vbNewLine
                    Next
                End With
            Catch ex As Exception
                ' When the update info file is not found or the server is unavaible, an exception will occure, which is catched here
            End Try
        End Sub

        ''' <summary>Raise the correct event when the info check is completed</summary>
        Protected Overridable Sub bgwUpdateInfoWorker_RunWorkerCompleted() Handles bgwUpdateInfoWorker.RunWorkerCompleted
            RaiseEvent UpdateCheckCompleted(Me, New EventArgs)
            If Me.FoundUpdateInfo Then
                RaiseEvent UpdateInfoDownloaded(Me, New EventArgs)
            Else
                RaiseEvent NoUpdateInfoFound(Me, New EventArgs)
            End If
        End Sub

        ''' <summary>Attempt to download the updater and store it on the correct location</summary>
        Protected Overridable Sub bgwUpdateFileWorker_DoWork() Handles bgwUpdateFileWorker.DoWork
            Try
                If File.Exists(Me.UpdaterPath) Then File.Delete(Me.UpdaterPath)
                webClient.DownloadFile(Me.Info.updatePath & "/" & Me.Info.updateFile, Me.UpdaterPath)
            Catch ex As Exception
                ' When the updater is not found or the server is unavaible, an exception will occure, which is catched here
            End Try
        End Sub

        ''' <summary>Raise the correct event when the download of the updater is completed</summary>
        Protected Overridable Sub bgwUpdateFileWorker_RunWorkerCompleted() Handles bgwUpdateFileWorker.RunWorkerCompleted
            RaiseEvent UpdateDownloadCompleted(Me, New EventArgs)
            If Me.UpdaterDownloaded Then
                RaiseEvent UpdateFileDownloaded(Me, New EventArgs)
            Else
                RaiseEvent NoUpdateFileFound(Me, New EventArgs)
            End If
        End Sub

        ''' <summary>Dispose the updaters recources</summary>
        Protected Overridable Sub Dispose(ByVal disposing As Boolean)
            If Not Me.m_isDisposed Then
                If disposing Then
                    bgwUpdateFileWorker.Dispose()
                    bgwUpdateInfoWorker.Dispose()
                    webClient.Dispose()
                End If
                Me.Info = Nothing
            End If
            Me.m_isDisposed = True
        End Sub

        ''' <summary>Free the resources before the memory is reclaimed by the GC</summary>
        Protected Overrides Sub Finalize()
            Me.Dispose(False)
            MyBase.Finalize()
        End Sub
#End Region

#Region "Properties"
        ''' <summary>Gets or sets the object containing info about the update</summary>
        Public Property Info() As UpdateInfo
            Get
                Return m_info
            End Get
            Set(ByVal value As UpdateInfo)
                If m_info IsNot value Then
                    m_info = value
                    RaiseEvent InfoChanged(Me, New EventArgs)
                End If
            End Set
        End Property

        ''' <summary>Gets or sets the startup path of the application. This property needs to be set before the updater is downloaded</summary>
        Public Property StartupPath() As String
            Get
                Return m_statupPath
            End Get
            Set(ByVal value As String)
                If m_statupPath <> value Then
                    m_statupPath = value
                    RaiseEvent StartupPathChanged(Me, New EventArgs)
                End If
            End Set
        End Property

        ''' <summary>Gets or sets the name of the application</summary>
        Public Property ApplicationName() As String
            Get
                Return m_appName
            End Get
            Set(ByVal value As String)
                If m_appName <> value Then
                    m_appName = value
                    RaiseEvent ApplicationNameChanged(Me, New EventArgs)
                End If
            End Set
        End Property

        ''' <summary>Gets or sets the version of the application</summary>
        Public Property ApplicationVersion() As Version
            Get
                Return m_appVersion
            End Get
            Set(ByVal value As Version)
                If m_appVersion IsNot value Then
                    m_appVersion = value
                    RaiseEvent ApplicationVersionChanged(Me, New EventArgs)
                End If
            End Set
        End Property

        ''' <summary>Gets or sets the path to the file containing update info</summary>
        Public Property UpdatePath() As String
            Get
                Return m_update_path
            End Get
            Set(ByVal value As String)
                If m_update_path <> value Then
                    m_update_path = value
                    RaiseEvent UpdatePathChanged(Me, New EventArgs)
                End If
            End Set
        End Property

        ''' <summary>Gets or sets the name of the file containing update info</summary>
        Public Property UpdateFile() As String
            Get
                Return m_update_file
            End Get
            Set(ByVal value As String)
                If m_update_file <> value Then
                    m_update_file = value
                    RaiseEvent UpdateFileChanged(Me, New EventArgs)
                End If
            End Set
        End Property

        ''' <summary>Gets if the avaible update is newer then the current version</summary>
        Public ReadOnly Property UpdateIsNewer() As Boolean
            Get
                Return Me.Info.updateVersion > Me.ApplicationVersion
            End Get
        End Property

        ''' <summary>Gets the update version formatted as a string, without the revistion number</summary>
        Public ReadOnly Property UpdateVersion() As String
            Get
                Return Me.Info.updateVersion.major.ToString & "." & Me.Info.updateVersion.minor.ToString & "." & Me.Info.updateVersion.build.ToString
            End Get
        End Property

        ''' <summary>Gets if an update info file was found</summary>
        Public ReadOnly Property FoundUpdateInfo() As Boolean
            Get
                Return Me.Contents.Length > 0
            End Get
        End Property

        ''' <summary>Gets if a newer update was found</summary>
        Public ReadOnly Property FoundUpdate() As Boolean
            Get
                Return Me.FoundUpdateInfo And Me.UpdateIsNewer
            End Get
        End Property

        ''' <summary>Gets if there was an internet connection avaible during the last download attempt</summary>
        Public ReadOnly Property FoundConnection() As Boolean
            Get
                Return m_hasFoundConnection
            End Get
        End Property

        ''' <summary>Gets if the updater has been successfully downloaded and placed in the correct location</summary>
        Public ReadOnly Property UpdaterDownloaded() As Boolean
            Get
                Return File.Exists(Me.UpdaterPath) And m_hasDownloaded
            End Get
        End Property

        ''' <summary>Gets or sets the recieved contents of the update info file</summary>
        Private Property Contents() As String
            Get
                Return m_contents
            End Get
            Set(ByVal value As String)
                m_contents = value
            End Set
        End Property

        ''' <summary>Gets the full path of the updater</summary>
        Private ReadOnly Property UpdaterPath() As String
            Get
                Return Me.StartupPath & "/" & autorunAppName
            End Get
        End Property
#End Region

    End Class
#End Region

End Namespace

Cheers,
BN
 
Generally you will call Dispose on any objects that are assigned to fields of your class, which is what you've done. I'd just question why you're setting Info to Nothing. It won't really hurt but what is it supposed to achieve?
 
jmcilhinney said:
I'd just question why you're setting Info to Nothing. It won't really hurt but what is it supposed to achieve?
This is part of the "TODO: set large fields to null." template. If the String fields here also could contain large amounts of text I'd reset these also. If variable doesn't go out of scope it will help minimizing actual memory usage until it does.
 
JohnH is correct, that is indeed what I attempted to do :)

So correct me if I'm wrong: disposing all objects and setting all fields to Nothing would be more efficient although it would take more time to program.

If there a way to simply set everything to nothing, or should I not use .Dispose for this, but for example set the instance of the class itself to nothing?

Cheers
BN
 
Setting the variable holding the instance of the class itself to Nothing has no effect other than to dereference it, the object instance lives on until all references is cleared and it is at some point collected by GC. GC can't deallocate the memory held by that object until it knows no part of program stills hang on to it, and until that happens more memory is locked if class fields stores large amount of data. (I would not see a String variable holding a file path as a potentially large field)
or should I not use .Dispose for this
That being said, as you know Dispose is not only about releasing memory, but also close other managed and not managed resources, some times a managed resource will also allocated unmanaged resources. The only way to close/release these is to call a Close/Dispose method. Unmanaged resources that is not correctly released may not be cleaned up at all until computer is shut down, because no other part or OS is managing them.
 
Back
Top