Manually dispose of class instance in VB.Net - vb.net

Yes, I realize Garbage Collector takes care of freeing up memory, and I also know of the inefficiencies in clearing up memory manually, however for educational purposes I would like to know how to dispose a class instance in VB.Net.

look at the example given in MSDN: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
to use it, you can either use Using block or call Dispose() directly. for example:
' use Using Block:
Using r = New MyResource(100)
Console.WriteLine(r.ToString())
End Using
' call Dispose directly:
Dim r = New MyResource(100)
Console.WriteLine(r.ToString())
r.Dispose()

Related

VB.net Variable Scope and SQL Reader

I have an object that I created that handles SQL queries. The function that actually handles the query is:
Function Execute_Command(ByVal strSQLCommand As String)
Dim sqlReturnInfo As SqlDataReader
Dim sqlQuery As New SqlCommand
sqlQuery = sqlMainDBCon.CreateCommand()
sqlQuery.CommandText = strSQLCommand
sqlReturnInfo = sqlQuery.ExecuteReader
Return sqlReturnInfo
End Function
When I execute the code it works fine the first time, but the 2nd time I get an error saying that sqlReturnInfo is not closed.
I fixed the problem by putting sqlReturnInfo = Nothing at the top after the declaration.
My understanding though, is that once this function finishes, the sqlReturnInfo should go out of scope and be destroyed automatically, and then once the function runs again the sqlReturnInfo is recreated as a new object, therefore sqlReturnInfo = nothing should not be nescessary/
I have seen this type of issue in one or two other areas in my code as well, out of scope variables persisting...
Am I doing something wrong, or is my understanding of variable scope incorrect?
Thanks
-RW
Garbage Collection - not all objects follow that rule(COM objects, Streams, graphics objects, Fonts, Bitmaps(the worst), etc...), dispose when done no matter what method you use(Sub/Function). Using/End Using blocks are the best - it takes care of that for you. My rule of thumb, if you see a Dispose method on a class object - Use It! The reason they have them is the engineer knew it would have problems getting collected so they made a method to assist with it.
Your object has the following statement on it:
You must explicitly call the Close method when you are through using the SqlDataReader to use the associated SqlConnection for any other purpose.
You need to use the .Close() function when you are done:
sqlReturnInfo.Close()
See: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.close%28v=vs.110%29.aspx

When should an Excel VBA variable be killed or set to Nothing?

I've been teaching myself Excel VBA over the last two years, and I have the idea that it is sometimes appropriate to dispose of variables at the end of a code segment. For example, I've seen it done in this bit adapted from Ron de Bruin's code for transferring Excel to HTML:
Function SaveContentToHTML (Rng as Range)
Dim FileForHTMLStorage As Object
Dim TextStreamOfHTML As Object
Dim TemporaryFileLocation As String
Dim TemporaryWorkbook As Workbook
...
TemporaryWorkbook.Close savechanges:=False
Kill TemporaryFileLocation
Set TextStreamOfHTML = Nothing
Set FileForHTMLStorage = Nothing
Set TemporaryWorkbook = Nothing
End Function
I've done some searching on this and found very little beyond how to do it, and in one forum post a statement that no local variables need to be cleared, since they cease to exist at End Sub. I'm guessing, based on the code above, that may not be true at End Function, or in other circumstances I haven't encountered.
So my question boils down to this:
Is there somewhere on the web that explains the when and why for variable cleanup, and I just have not found it?
And if not can someone here please explain...
When is variable cleanup for Excel VBA necessary and when it is not?
And more specifically... Are there specific variable uses (public variables?
Function-defined variables?) that remain loaded in memory for longer
than subs do, and therefor could cause trouble if I don't clean
up after myself?
VB6/VBA uses deterministic approach to destoying objects. Each object stores number of references to itself. When the number reaches zero, the object is destroyed.
Object variables are guaranteed to be cleaned (set to Nothing) when they go out of scope, this decrements the reference counters in their respective objects. No manual action required.
There are only two cases when you want an explicit cleanup:
When you want an object to be destroyed before its variable goes out of scope (e.g., your procedure is going to take long time to execute, and the object holds a resource, so you want to destroy the object as soon as possible to release the resource).
When you have a circular reference between two or more objects.
If objectA stores a references to objectB, and objectB stores a reference to objectA, the two objects will never get destroyed unless you brake the chain by explicitly setting objectA.ReferenceToB = Nothing or objectB.ReferenceToA = Nothing.
The code snippet you show is wrong. No manual cleanup is required. It is even harmful to do a manual cleanup, as it gives you a false sense of more correct code.
If you have a variable at a class level, it will be cleaned/destroyed when the class instance is destructed. You can destroy it earlier if you want (see item 1.).
If you have a variable at a module level, it will be cleaned/destroyed when your program exits (or, in case of VBA, when the VBA project is reset). You can destroy it earlier if you want (see item 1.).
Access level of a variable (public vs. private) does not affect its life time.
VBA uses a garbage collector which is implemented by reference counting.
There can be multiple references to a given object (for example, Dim aw = ActiveWorkbook creates a new reference to Active Workbook), so the garbage collector only cleans up an object when it is clear that there are no other references. Setting to Nothing is an explicit way of decrementing the reference count. The count is implicitly decremented when you exit scope.
Strictly speaking, in modern Excel versions (2010+) setting to Nothing isn't necessary, but there were issues with older versions of Excel (for which the workaround was to explicitly set)
I have at least one situation where the data is not automatically cleaned up, which would eventually lead to "Out of Memory" errors.
In a UserForm I had:
Public mainPicture As StdPicture
...
mainPicture = LoadPicture(PAGE_FILE)
When UserForm was destroyed (after Unload Me) the memory allocated for the data loaded in the mainPicture was not being de-allocated. I had to add an explicit
mainPicture = Nothing
in the terminate event.

VB.NET: Nesting "Using" for database access

I'm wondering if this is a good way of doing data access, in terms of all the database objects being properly closed and disposed? For example:
Using conn As New SqlConnection(MyConnectionString)
Using cmd As New SqlCommand("some SQL here", conn)
... add parameters ...
conn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader()
While dr.Read()
... do stuff ...
Wend
End Using
End Using
End Using
Is nesting Using like acceptable practice? If I exit the method at some point within the Read() loop, will the use of Using like this ensure all objects are cleaned up properly regardless?
Using guarantees orderly disposal in an implicit try/finally block.
' THE FOLLOWING TRY CONSTRUCTION IS EQUIVALENT TO THE USING BLOCK
Dim resource As New resourceType
Try
' Insert code to work with resource.
Catch ex As Exception
' Insert code to process exception.
Finally
' Insert code to do additional processing before disposing of resource.
resource.Dispose()
End Try
Nested usings work in a similar fashion. If you exit a block of code, it will execute the finally block, and properly dispose your objects.
http://msdn.microsoft.com/en-US/library/htd05whh(v=VS.80).aspx
To add, the Using block will "behind the scenes" add a Try Finally statement. In the finally statement it will call IDisposable.Dispose on the object. In other words, no matter what you do or what happens, the object will get disposed.
Yes, this is ok. The Dispose method of IDisposable objects is always called.
PS: In this case, the Dispose method also contains the Close method.
You are writing VB.Net, so this only partially applies, but for the C# folks out there using StyleCop, multiple using statements like this will cause exception 2202 in StyleCop.
There is a lengthy section at the msdn link of dissenting comments as to the usefulness of this rule in stylecop.
I will not make a judgment call as to whether you should heed StyleCops warnings for C# in your VB.Net code.

Should you call close even within a Using block

Using sr As New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd
End Using
Using sr As New System.IO.StreamReader("C:\test.txt")
sr.ReadToEnd
End Using
This is equivalent to:
sr = New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd
sr.Dispose
sr = New System.IO.StreamReader("C:\test.txt")
sr.ReadToEnd
sr.Dispose
Am I right in saying the attempt to read the file may fail if the Garbage collector had not got around to disposing the StreamWriter and closing the file. If so where is the benefit is using the Using Statement in this case. Is is better practice to use
Using sr As New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd
sr.close()
End Using
It is a best practice to always the Using statement because if an exception is thrown during the reading the stream might never be disposed and your application will leak a file handle. If this is a desktop application the process will probably die and release the handle but in a web application not releasing unmanaged resources such as file handles could be catastrophic.
Also you don't need to call Close on your stream if you are calling Dispose.
Remark: if you want to read the contents of a text file into a string you could directly do this instead of going through the pain of instantiating a StreamReader, reading it to the end and disposing it:
Dim data = File.ReadAllText("C:\test.txt");
No, the Garbage Collector does not dispose the object, calling Dispose does that, and the using block makes sure that happens. The object may still be in memory, but the file will have been dealt with.
If you didn't call close or dispose (either manually or by use of the using block), and the object got collected it would then be finalised (slowing up garbage collection) and that would close the file handle. But this last-chance is different to dispose.
You don't have to call close on the file within the using block, but you are free to. This may be a good idea to release the handle quickly (not often an issue with file handles, more often an issue with pooled database connections), with the using block giving you an added guarantee (it's always safe to call dispose, even if its already been called).
Actually, it is equivalent to this: The Finally blocks will guarantee the Dispose is called and everything is cleaned up in the event of an exception.
Try
sr = New System.IO.StreamWriter("C:\test.txt")
sr.WriteEnd()
Finally
sr.Dispose()
End Try
Try
sr = New System.IO.StreamReader("C:\test.txt")
sr.ReadToEnd()
Finally
sr.Dispose()
End Try
Think if you are done and don't care too much about it after, can let the dispose just happen
BUT dispose may take a while, so if you need to use the file (e.g. pass to another app, move to new location, or any other use of the file), then probably should Close it explicitly
Close should release any locks, expect this will fail:
dim fn as string = "C:\temp.txt"
Using sr As New System.IO.StreamWriter(fn)
sr.WriteLine("Junk")
' sr.close
End Using
system.io.file.delete(fn)
Expect the delete to throw an error, since file dispose may not yet have happened
If you explicitly close (e.g. un-comment the close), then should always succeed

VB.Net Running Threading with Reflected Objects

Running into problems creating objects through reflection and then running them on multiple threads.
I just cannot seem to figure out what I need to here:
For Each WorkerNode As XmlNode In oRunSettings.GetWorkerValues
Dim sWorkerName = WorkerNode.Attributes(SETTING_NAME_ID).Value
Dim oWorkerType As Type = Type.GetType(String.Format("Worker.{0}", sWorkerName))
Dim oWorker As Object = Activator.CreateInstance(oWorkerType)
Dim tWorker As Thread = New Thread(AddressOf oWorker.Process)
tWorker.Start()
Next
It is causing errors at the "AddressOf" because Object does not have a method called that. Do I need to do something with an interface?
First of all I want to say that I've never wrote code in VB so I can be completely wrong here but I'll try anyway.
It seems that you hold the created instance as Object instead of it's correct type.
Object does not contain method named Process, hence the error.
try casting the object to the correct type.
I hate when people answer their own question, but while waiting for an answer, I realized that I could just cast the object as its base object, and set the reflection from there. That is working now.