Bug in .NET 1.1?

C

Cory Nelson

The following code is causing the exception
"System.InvalidOperationException: Handle is not initialized". From my
understanding, objects in a class are expected to be valid during the
destructor.

This is causing the exception (note, if you explicitly call m.Close(),
this does not happen):

public class DbManager {
private readonly SqlConnection con;

public DbManager() {
con=new SqlConnection("Data Source=<source>; User ID=<user>;
Password=<password>;Initial Catalog=<database>");
Open();
}

~DbManager() {
Close();
}

public void Open() {
con.Open();
}

public void Close() {
con.Close();
}
}

static void Main(string[] args) {
DbManager m=new DbManager();
}
 
G

Guest

hi Cory......

The programmer has no control on when the destructor is going to be executed
because this is determined by the Garbage Collector. The garbage collector
checks for objects that are no longer being used by the application. It
considers these objects eligible for destruction and reclaims their memory.
Destructors are also called when the program exits. When a destructor
executes what is happening behind the scenes is that the destructor
implicitly calls the Object.Finalize method on the object's base class.
Therefore, the preceding destructor code is implicitly translated to:

protected override void Finalize()
{
try
{
// Cleaning up .
}
finally
{
base.Finalize();
}
}
Now, let us look at an example of how destructors are called. We have three
classes A, B and C. B is derived from A, and C is derived from B. Each class
has their own constructors and destructors. In the main of the class App, we
create an object of C.

using System;
class A
{
public A()
{
Console.WriteLine("Creating A");
}
~A()
{
Console.WriteLine("Destroying A");
}
}

class B:A
{
public B()
{
Console.WriteLine("Creating B");
}
~B()
{
Console.WriteLine("Destroying B");
}

}
class C:B
{
public C()
{
Console.WriteLine("Creating C");
}

~C()
{
Console.WriteLine("Destroying C");
}
}
class App
{
public static void Main()
{
C c=new C();
Console.WriteLine("Object Created ");
Console.WriteLine("Press enter to Destroy it");
Console.ReadLine();
c=null;
//GC.Collect();
Console.Read();
}

}
As we expect, the constructors of base classes will be executed and program
will wait for the user to press 'enter'. When this occurs, we set the object
of class C to null. But the destructors are not executing ..!!?? As we
already said, the programmer has no control on when the destructor is going
to be executed because the Garbage Collector determines this. But the
destructors are called when the program exits. You can check this by
redirecting the o/p of the program to a text file. I have the output here.
Notice that the destructors of the base classes are called because behind the
scenes base.Finalize() is called.

Creating A
Creating B
Creating C
Object Created
Press enter to Destroy it
Destroying C
Destroying B
Destroying A
So, what do you do if you want to call the destructors once you are finished
using the object? There are two ways:

Call the Garbage collector to clean up.
Implement Dispose method of IDisposable interface.

Hope this helps in why explicitly calling m.close() does not raise the error
and moreover check these hints also.

Note 1: Do not use destructor if your class does not use native / unmanaged
resources. If you do so, you create unnecessary work for the garbage
collector.

Note 2: If you implement the IDisposable and a destructor, you should call
the Dispose method from the destructor to force the object to release
resources immediately.

Hope the above explanation might be useful for you.
Regds
Kannan.V

Cory Nelson said:
The following code is causing the exception
"System.InvalidOperationException: Handle is not initialized". From my
understanding, objects in a class are expected to be valid during the
destructor.

This is causing the exception (note, if you explicitly call m.Close(),
this does not happen):

public class DbManager {
private readonly SqlConnection con;

public DbManager() {
con=new SqlConnection("Data Source=<source>; User ID=<user>;
Password=<password>;Initial Catalog=<database>");
Open();
}

~DbManager() {
Close();
}

public void Open() {
con.Open();
}

public void Close() {
con.Close();
}
}

static void Main(string[] args) {
DbManager m=new DbManager();
}
 
C

Cory Nelson

Thankyou for answering quick, but I'm afraid you didn't understand the
problem.

Putting destructors being unpredictable and sometimes hard on the GC
aside, this is still code that shoudn't be raising exceptions. "con"
should not be mucked with by the GC until the destructor of DbManager
is called.
 
T

Tiberiu Covaci[MCAD.NET]

Hi Cory,

As Kannan said, the behaviour is the correct one. Why? The GC guaranties
only that the destructor is called, if you have one, but does not guarantee
the order in which your destructors will be called. And I will explain why
this behaviour. When your DbManager object is no longer refferenced in your
programm, your object will become unreacheble, but you will still have one
refference to it, in the Finalize Q. And because con is referenced only by
DbManager, will be unreachable as well but will have one refference to it,
in the Finalize Q. And because of that you don't have a guarantee that your
con wasn't already destroied when you try to Close it. Because you have a
destructor in con, then you will not need one in DBManager, if con is the
only resource you are using in your DBManager.

Regards,

Tiberiu Covaci
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top