Re: Handle is not initialized

  • Thread starter Thread starter David Browne
  • Start date Start date
D

David Browne

SC said:
Hi!

Here's my code:
.. . .
Alright, to me it doesn't seem like there's a whole lot in there.
UConnection and UDataReader are "universal" objects able to connect to any
data source by just specifying it using the enum. Anyways, when the program
exits, I get the following error (using a SQL server in this case):
Handle is not initialized.
mscorlib
at System.WeakReference.get_Target()
at System.Data.SqlClient.SqlConnection.CloseReader()
at System.Data.SqlClient.SqlConnection.Close()
at UniversalData.UConnection.Close()
at UniversalData.UData.Disconnect()
System.Object get_Target()

This all happens at the cn.Close() command of the Disconnect method.
Though, in debug, I cannot see anything wrong with my cn object. The status
says that it's an open connection and every property is set correctly.
What can I do to avoid this error (and actually close the connection and
the datareader when we forget to do so and the system disposes of the
object)?
Your problem is here:

~UData()
{
//We do this just in case... It's safer!
Disconnect();
}


It is an error to access a SqlConnection in your finalizer in any way.
Period. There's some funky connection pooling stuff in SqlClient which is
incompatable with accessing the connection in a finalizer. By the time your
finalizer runs, your SqlConnection could be in use by another thread!

The problem you are actually seeing is because the finalization order is
indeterminate, so especially when the final GC is running at CLR shutdown
your finalizer can try to access previously finalized objects. You can work
around this particular issue by checking if the GC is at shutdown, and just
skipping your finalization code, but your real problem is that you shouldn't
be disconnecting in your finalizer at all.

Moreover UData should implement IDisposable, and IDisposable.Dispose should
close (or Dispose) the connection and then run GC.SupressFinalize(me), to
remove the instance from the Finalization Queue.

David
 
SC said:
----- David Browne wrote: -----

Moreover UData should implement IDisposable, and IDisposable.Dispose should
close (or Dispose) the connection and then run GC.SupressFinalize(me), to
remove the instance from the Finalization Queue.


Alright, I understand everything you said before except how to do one
thing: My major fear is that someone will use my code and forget to close
the connection before exiting. Whether I use my method or use the dispose
methodology, the user always has to remember to add code to call at least
one method to free the ressources (either the Dispose method that is not
called automatically or my Disconnect method). I would love an event-driven
"assurance" based on the destruction of the object. Isn't that possible?
It's a false sense of security. If you wait for the Garbage Collector to
close your connections, your application will fail under load anyway. There
is no magic bullet for closing connections, you must rely on programmer
diligence. That's just a weakness in .net. That's also why you need to
implement the Disposable pattern. It tells programmers how to use your
type.

David
 
Back
Top