Disposing data table? - vb.net

I was reading this msdn article today and I am curious about finally part with disposing datatable. Is that really necessary? why should we dispose a datatable? If I exit the function or sub, is it not releasing the resources?
Explanation in the article is;
Dispose of the temporary data tables to release the resources.
Private Sub UpdateDB()
Dim deletedChildRecords As NorthwindDataSet.OrdersDataTable = _
CType(NorthwindDataSet.Orders.GetChanges(Data.DataRowState.Deleted), NorthwindDataSet.OrdersDataTable)
Dim newChildRecords As NorthwindDataSet.OrdersDataTable = _
CType(NorthwindDataSet.Orders.GetChanges(Data.DataRowState.Added), NorthwindDataSet.OrdersDataTable)
Dim modifiedChildRecords As NorthwindDataSet.OrdersDataTable = _
CType(NorthwindDataSet.Orders.GetChanges(Data.DataRowState.Modified), NorthwindDataSet.OrdersDataTable)
Try
If deletedChildRecords IsNot Nothing Then
OrdersTableAdapter.Update(deletedChildRecords)
End If
CustomersTableAdapter.Update(NorthwindDataSet.Customers)
If newChildRecords IsNot Nothing Then
OrdersTableAdapter.Update(newChildRecords)
End If
If modifiedChildRecords IsNot Nothing Then
OrdersTableAdapter.Update(modifiedChildRecords)
End If
NorthwindDataSet.AcceptChanges()
Catch ex As Exception
MessageBox.Show("An error occurred during the update process")
' Add code to handle error here.
Finally
If deletedChildRecords IsNot Nothing Then
deletedChildRecords.Dispose()
End If
If newChildRecords IsNot Nothing Then
newChildRecords.Dispose()
End If
If modifiedChildRecords IsNot Nothing Then
modifiedChildRecords.Dispose()
End If
End Try
End Sub

To answer your question, is it necessary to dispose a datatable? The concensus is no, here's my thought.
Setting things to null or nothing doesn't remove the memory used by the instance of the object. Neither does dispose. The GC does, when it runs. Remember, when you have a reference variable, you have a pointer to an object. When you repoint that variable to a null address, it doesn't delete the data at the previous address, nor does it free the memory.
Basically, dispose is useful for preparing your objects for being destroyed, but it doesn't actually release the memory used by the object. If you're dealing with resources that need cleaning up, like open streams, database connections, things like that, dispose is great.

Related

VB.NET Releasing Excel file after reading so it can be overwritten

I am having the same issue that many before me have had, and I have found several threads on the issue but my application of their fixes have not yielded any change.
I am reading an excel file and populating a DataGridView with it. Very simply the user can modify it and then save it. The problem, like the other threads, is that the program has such a tight grip on the file I can't overwrite it.
Among the many fixes offered, Garbage Collection was the most frequently mentioned, but my results are unchanged. I have tried disposing of the OLEDB connection, commands, adapters and datasets also without success.
I've been running through several different examples and tutorials to write this program and so if these fixes are required, I've obviously implemented them in the wrong spot.
Here is the reading block which happens on the form load (I've removed all my attempts to fix it to unclutter the code):
Private Sub Inventory_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Using MyConnection = New System.Data.OleDb.OleDbConnection("provider=Microsoft.Jet.OLEDB.4.0;Data Source='c:\AllTrade\Inventory.xlsx';Extended Properties=Excel 8.0;")
Using MyCommand = New System.Data.OleDb.OleDbDataAdapter("select * from [InventorySheet$]", MyConnection)
DtSet = New System.Data.DataSet
MyCommand.Fill(DtSet)
InventoryGridView.DataSource = DtSet.Tables(0)
MyConnection.Close()
End Using
End Using
End Sub
Here is the saving block (This is the code that generates the "File in Use" error):
Private Sub UpdateInventory_Click(sender As Object, e As EventArgs) Handles UpdateInventory.Click
Dim ExcelApp As New Excel.Application()
ExcelApp.Application.Workbooks.Add(Type.Missing)
For i As Integer = 0 To InventoryGridView.Rows.Count - 1
Dim row As DataGridViewRow = InventoryGridView.Rows(i)
For j As Integer = 0 To row.Cells.Count - 1
ExcelApp.Cells(i + 1, j + 1) = row.Cells(j).Value
Next
Next
ExcelApp.ActiveWorkbook.SaveAs("C:\Alltrade\Inventory.xlsx")
ExcelApp.ActiveWorkbook.Saved = True
ExcelApp.Quit()
End Sub
What's the trick to let go of the file? If the GC.Collect() and GC.WaitForPendingFinalizers() are required, where would they go?
I appreciate any help and apologize since I haven't been able to successfully implement the other answers from similar threads.
You need to marshal to release the COM object: ExcelApp...
Private Sub ReleaseObject(ByVal obj As Object)
Try
Dim intRel As Integer = 0
Do
intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
Loop While intRel > 0
Catch ex As Exception
MsgBox("Error releasing object" & ex.ToString)
obj = Nothing
Finally
GC.Collect()
End Try
End Sub
You can call this method like this at the end of your sub.
ReleaseObject(ExcelApp)
You can get more here Excel application not quitting after calling quit
EDIT
I also noticed your connection string is wrong for the newer .xlxs file extention...
Normal ConnectionString : (work for xls files)
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=YES;\""
Office 2007 ConnectionString : (work for xlsx files)
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0;HDR=YES;\""
After much research and frustration, I found a solution.
The connection string of my OleDB connection needs the tidbit added: OLE DB Services = -4 which disables connection pooling. As it happens, the connection is not disposed of (which was the initial hypothesis) when the connection is closed, but instead dumps the connection back into the pool.
Another forum had suggested OLE DB Services = -2 which was supposed to do the same thing, but had no effect in my instance. It's possible it varies between versions but I haven't researched this to conclude that for certain (or someone typoed in one of the forums)
No further code was required in my program to dump the OleDB connection's hold on the file. MyConnection = Nothing and the line that drains the pool followed by a GC.Collect were also recommended but did not resolve my symptoms.
Thanks everyone for the input

How do I solve 'System.OutOfMemoryException'

I have a Windows Service application. It is a very busy application. It is supposed to run continuously looking for things to do. After it runs for a while I get
Exception of type 'System.OutOfMemoryException' was thrown.
It can happen at different times but usually a this paragraph:
Private Shared Function GetUnprocessedQueue() As Boolean
Try
Dim l_svcOOA As New svcITGOOA.IsvcITGOOAClient(OOAProcessing.cGlobals.EndPoint_ITGOOA)
Dim l_iFilter As New svcITGOOA.clsFilter
With l_svcOOA
With l_iFilter
.FilingType = OOAProcessing.cGlobals.FilingType
End With
m_ReturnClass = .itgWcfOOA(1, cGlobals.DatabaseIndicator, svcITGOOA.eOOAAction.GetUnprocessedQueue, l_iFilter, 71)
Return CompletedGetUnprocessedQueue(m_ReturnClass)
End With
Catch ex As Exception
ExceptionHandling(ex, "GetUnprocessedQueue " & m_Application)
Return False
End Try
End Function
This is using a wcf service to read a queue. It reads the queue every two minutes to see if new records have been added to it.
Please help me solve this. I don’t know where to start.
The OutOfMemoryException exception occurs when the GC has completed a cycle of collection but the memory is not available even after that. I couldn't make out what the above code snippet does, but I think using Weak References for objects could be useful.
I had a timer that was generated within the same paragraph that I was setting
For example
m_svcTimer = New Timers.Timer With {.Interval = m_Interval, .Enabled = True}
AddHandler m_svcTimer.Elapsed, AddressOf StartTheQueueIfTime
m_svcTimer.Enabled = True
m_svcTimer.Start()
was within the paragraph StartTheQueueIfTime. I thought this would be a way to change the time interval. Instead it kept creating new events. Finally too many caused my crash.
Bob

CA2000: Dispose objects before losing scope

I'm getting the error in this part of code when I try to run the code analysis in my project.
//Code
Private Sub SaveMaterialStatus(ByVal status As String)
Dim cSMaterialInput As CSMaterialInput = Nothing
Try
If ViewState("CSInput") IsNot Nothing Then
'Create a new transaction
cSMaterialInput = New CSMaterialInput
cSMaterialInput = ViewState("CSInput")
cSMaterialInput.CSStatus = status
CSMaterialInputMethods.SaveToDatabase(cSMaterialInput, Environment.UserName, Environment.MachineName)
End If
Catch ex As Exception
Throw
Finally
If cSMaterialInput IsNot Nothing Then cSMaterialInput.Dispose()
End Try
End Sub
Detailed Error:
CA2000 Dispose objects before losing scope In method 'ShowSummary.SaveMaterialStatus(String)', call System.IDisposable.Dispose on object 'cSMaterialInput' before all references to it are out of scope. xxxx.CostingTool.Presentation ShowSummary.aspx.vb 790
Where i'm wrong??
cSMaterialInput = New CSMaterialInput
That's where the problem started. You immediately reassign the variable in the next statement so the object you created never gets disposed. Which triggered the CA2000 warning. There is just no point to creating a new object that you never use. Which leaves little else in the method:
Private Sub SaveMaterialStatus(ByVal status As String)
Dim cSMaterialInput = ViewState("CSInput")
If cSMaterialInput IsNot Nothing Then
cSMaterialInput.CSStatus = status
CSMaterialInputMethods.SaveToDatabase(cSMaterialInput, Environment.UserName, Environment.MachineName)
End If
End Sub
With the Nothing test still a significant code smell. It is just hiding a bug when your program tries to save nothing.

Why to set an object to Nothing in the Finally block?

In this VB.NET code:
Dim o as SomeClass
Try
o = new SomeClass
'call some method on o here
Catch(...)
...
Finally
o = Nothing
End Try
Why is there a need to set o to Nothing? What if i don't set it to Nothing in the Finally block? What i think is that it is OK if you don't set it to Nothing because the object will be marked for GC.
If the object is unsafe to use out of the try catch should this be done. If this was a stream for example you'd see the stream closed and then set to nothing. It is not always the right thing to do but this code is seen a lot.
consider this code
Sub Main()
Dim o As String
Try
o = "Hello"
Console.Out.WriteLine("hi {0}", o)
Catch ex As Exception
' do something here
Finally
o = Nothing
End Try
' unable to do something here
End Sub
Allthough it is a silly example it does mean you cannot reference o outside now because it is no longer set to an instance of an object. That is why it is done by a lot of people. If you are in a function and a function ends at that point there is no need to set to Nothing as the object falls out of scope however lots of people will set stuff to Nothing out of habit I'd consider that incorrect and bad code design
It's because the object is not safe to use outside the the try.. catch.. finally block. It's not guaranteed it's in a consistent state, so it's set to Nothing to make it obvious t's not supposed to be used.

What is the best practice for ReadOnly Properties/Functions in VB.Net?

I'm not too new to VB.Net and the syntax, but I'm not an expert. I'm working on rewriting something in VB that was previously in C# and while I was doing so, I came across a "dilemna." I can have a ReadOnly Property:
Public ReadOnly Property MaximumIndenture()
Get
Try
'If the connection is closed, open it.'
If _dbConnection.State = ConnectionState.Closed Then
_dbConnection.Open()
End If
Dim dictFigureIndenture As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)
Using dbReader As IDataReader = ExecuteReader("SELECT PART_FIGURE, MAX(PART_INDENTURE) AS 'MAX_INDENT' FROM PARTS GROUP BY PART_FIGURE")
While dbReader.Read()
dictFigureIndenture.Add(dbReader("PART_FIGURE").ToString(), Convert.ToInt32(dbReader("MAX_INDENT").ToString()))
End While
End Using
'If the connection is open, do what you need to and/or close it.'
If _dbConnection.State = ConnectionState.Open Then
_dbConnection.Close()
End If
Return dictFigureIndenture
Catch ex As Exception
'An exception was thrown. Show it to the user so they can report it.'
MessageBox.Show(ex.Message)
'If the connection is open, do what you need to and/or close it.'
If _dbConnection.State = ConnectionState.Open Then
_dbConnection.Close()
End If
Return Nothing
End Try
End Get
End Property
And I can have a function that does the same thing:
Public Function MaximumIndenture() As Integer
Try
'If the connection is closed, open it.'
If _dbConnection.State = ConnectionState.Closed Then
_dbConnection.Open()
End If
Dim dictFigureIndenture As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)
Using dbReader As IDataReader = ExecuteReader("SELECT PART_FIGURE, MAX(PART_INDENTURE) AS 'MAX_INDENT' FROM PARTS GROUP BY PART_FIGURE")
While dbReader.Read()
dictFigureIndenture.Add(dbReader("PART_FIGURE").ToString(), Convert.ToInt32(dbReader("MAX_INDENT").ToString()))
End While
End Using
'If the connection is open, do what you need to and/or close it.'
If _dbConnection.State = ConnectionState.Open Then
_dbConnection.Close()
End If
Return dictFigureIndenture
Catch ex As Exception
'An exception was thrown. Show it to the user so they can report it.'
MessageBox.Show(ex.Message)
'If the connection is open, do what you need to and/or close it.'
If _dbConnection.State = ConnectionState.Open Then
_dbConnection.Close()
End If
Return Nothing
End Try
End Function
They both essentially do the same thing, but I'm not sure which would be more accepted in the community. Eventually I'd like to write a lot of open source code for people to use (most has probably already been written) but I definitely don't want someone to think what I'm doing is the best practice. Can anyone give me a laymen description as to which is better to use and why? Sorry if this is a duplicate post to someone else's, just curious. Thanks.
That should definitely be a method, not a property.
A property generally contains a light weight operation, like getting the value of a private variable and perhaps do some simple calculation or conversion. Something that pulls data from a database does definitely not match what's generally expected of a property.
Use a method, rather than a property,
if the operations is orders of
magnitude slower than a field access
would be. In particular operations
that access the network, or a file
system, should likely be methods.
Your code accesses a database: so it should be a method.
From the .NET Framework Design Guidelines 2nd Edition page 135
I can't promise you this is the best practice but I would say go with what feels more natural to you and makes more sense in the real world. I would say MaximumIndenture would make a better property than a function because it seems to me it is more of property of the object or a noun that belongs to it. I would use a function to do more of an opperation or verb that has some result. Those are my 2 cents. Hope it helps!