newbie: implementing destructors

R

R.A.M.

Hello,
I am learning .NET 2.0 (C#, ASP.NET, ADO.NET). I have one question to more
experienced programmers. When it makes sense to write destructor? What are
they used for in C#.NET?
Please help. Thank you!
/RAM/
 
G

Guest

Hi R.A.M,
destructors, referred to as finalizers officially in .Net only really have
one purpose in the .Net world which is as a SAFETY NET to clean up unmanaged
resources, these are resources that the CLR does not control or manage and
need to be cleaned up explicitly by your code. It is strongly recommended
that you should only write a finalizer if you really have to because adding a
finalizer to your class means it takes longer to garbage collect (look up on
www.live.com for more explanation on this). So an example would be that you
have some 3rd party DLL which internally allocates a chunk of memory, .Net
environment is not aware of this memory so at no point will it clean up this
memory during the execution of the process, it is upto your code to call some
explicit method in the DLL which cleans up the memory. Ideally you will have
some method in your class, let's call it Dispose for now which you can call
once you have finished using your object which will then call the 3rd party
DLLs method to clean up i.e.

class MyClass
{
//Call into some 3rd party dll which allocates memory
[DllImport("somedll.dll")]
private static extern void AllocateMemory();

//Frees memory allocated by a call to AllocateMemory()
[DllImport("somedll.dll")]
private static extern void CleanUpMemory();

public MyClass()
{
}

public void DoSomething()
{
//When this is called 10MB of memory is allocated
AllocateMemory();
}

//When you have finished using the object can call this to
//clean up the resources.
public void Dispose()
{
CleanUpMemory();
}
}

so from some other function you would to this:

void RunSomeCode()
{
MyClass mc = new MyClass();

//do some stuff, this is where unmanaged memory is allocated.
mc.DoSomething();

//make sure we clean up
mc.Dispose();
}

This is okay unless you either:
1. Forget to call Dispose (we will see later how we can stop this from
happening)
2. Throw an exception in the "//do some stuff" section of code at which
point the mc.Dispose() never gets called.

In both of the above scenarios you have a resource leak which is not a good
thing. A way around this is to put the cleanup code inside a finalizer, the
finalizer will get called by the GC when the object is no longer referenced
by any other objects, so we can now write:

class MyClass
{
bool cleanedUpMemory = false;

//Call into some 3rd party dll which allocates memory
[DllImport("somedll.dll")]
private static extern void AllocateMemory();

//Frees memory allocated by a call to AllocateMemory()
[DllImport("somedll.dll")]
private static extern void CleanUpMemory();


public MyClass()
{
}

public void DoSomething()
{
//When AllocateMemory is called, 10MB of memory is allocated
AllocateMemory();
}

~MyClass()
{
CleanUp();
}

//When you have finished using the object can call this to
//clean up the resources.
public void Dispose()
{
CleanUp();
}

private void CleanUp()
{
//Only want to do this once.
if(!this.cleanedUpMemory)
{
UnallocateMemory();
this.cleanedUpMemory = true;
}
}
}

So we are now more confident that if either we forget to call Dispose or an
exception is thrown so our Dispose call is skipped over at some point the
unmanaged resources are cleaned up. However the key point here is "AT SOME
POINT" you do not know when, maybe each class is allocating 10MB of memory,
but to .Net all it sees is the few KB it takes to allocate your managed
class, so the GC might not run even though you are using lots of memory, so
leaving it upto the garbage collector to run is a bad idea. Instead you want
some way or deterministically cleaning up the resources, you want to make
sure your Dispose method is always called. In that case you want to write
code like:

void RunSomeCode()
{
MyClass mc;
try
{
mc = new MyClass();

//do some stuff, this is where unmanaged memory is allocated.
mc.DoSomething();
}
finally
{
//make sure we clean up, even if an exception is thrown
if(mc != null)
{
mc.Dispose();
}
}
}

Now .Net provides a nicer shorthand way of writing the above, since you will
probably have the above pattern manytimes through your code, it is
implemented using the IDisposable interface which has a single method called
Dispose() (like we had in the example above), any object which implements
this interface can be used with the "using" keyword i.e. instead of the above
you can write:

using(MyClass mc = new MyClass())
{
mc.DoSomething();
}

when execution leaves the scope of the using statement the
IDisposable.Dispose method is called on the object evaluated in the using
statment (mc in this case), it also has the finally to make sure that the
Dispose is always called. So the final pattern for the object is:


class MyClass : IDisposable
{
//Indicates if the disposed method has been called
//already, we only want to process once.
bool disposed = false;

//Call into some 3rd party dll which allocates memory
[DllImport("somedll.dll")]
private static extern void AllocateMemory();

//Frees memory allocated by a call to AllocateMemory()
[DllImport("somedll.dll")]
private static extern void CleanUpMemory();

public MyClass()
{
}

public void DoSomething()
{
//Allocates 10MB of memory
AllocateMemory();
}

~MyClass()
{
//Want to call dispose to cleanup but also indicate that
//dispose was called by the Finalizer rather than by a user
//explicitly calling Dispose().
Dispose(false);
}

//When you have finished using the object can call this to
//clean up the resources.
public void Dispose()
{
//Cleanup and indicate a user called this i.e. the Finalizer did
//not, this is important to know, see the Dispose(bool disposing)
method
//for why that is the case.
Dispose(true);

//Now that we have cleaned up associated resources
//there is no need for the finalizer to be called, we can
//tell the GC to not call the Finalizer, this is good since now
//the object will not live for as long
GC.SuppressFinalize(this);
}

private void Dispose(bool disposing)
{
//Only want to do this once.
if(!this.disposed)
{
if(this.disposing)
{
//The user explicitly called Dispose, it was not called via
the GC,
//this is an important distinction because if a user called
Dispose
//we know the object must be refenced by another object, so
all
//internal managed references must still be valid since this
object
//is still referenced and it references it's internall
references. If we
//got into this method via a call from the finalizer then it
means that
//this object no longer has any references so that my also
be true for
//objects we reference, we cannot be sure in that case that
they have
//not already been garbage collected, so it is only safe to
access
//the managed resources inside this if statement when we
know a
//caller explicitly called Dispose()
}

//Cleanup unmanaged resources. Don't care if this method was
called
//indirectly by user of GC since only this class knows about the
unmanaged
//resources so it is always safe to assume they exist unless we
cleaned
//them up.

CleanUpMemory();
this.disposed = true;
}
}
}


Hope that gives you a starting point into finalizers in .Net

Mark.
 
D

Dave Sexton

Hi,

Destructors allow you to ensure the release of unmanaged resources that would
otherwise consume memory after the process that created them has terminated.

The simple disposal model allows you to release unmanaged resources on demand
by calling the Dispose method on an object that implements the IDisposable
interface.

class YourObject : IDisposable
{
public void Dispose()
{
// dispose of managed and unmanaged resources
}
}

If Dispose is never called, your unmanaged resources won't be released and so
there may be a memory leak in your program.

The standard ComponentModel disposal pattern consists of an implementation of
the IDisposable interface, a destructor and a custom Dispose method, which
takes a single boolean argument that indicates whether managed resources
should be disposed of as well as unmanaged resources.

class YourComponent : IDisposable
{
// This method serves as the IDisposable implementation
public void Dispose()
{
Dispose(true);

// prevent the destructor from being called by the garbage collector
// since we've already disposed of the unmanaged resources
GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
lock (this) // I recommend not locking on "this", however
{
// dispose of managed resources
}
}

// dispose of unmanaged resources
}

~YourComponent()
{
// the "disposing" argument is set to false because the object
// isn't being disposed, it's being finalized
Dispose(false);
}
}

If you don't call Dispose on an instance of YourComponent then Dispose(false)
will be called when the object is finalized by the garbage collector.

Just like in the simple disposal model, a finalizer shouldn't throw
exceptions.

The System.ComponentModel.Component class provides this implementation
already, so YourComponent could just derive from Component.

The Control class in the System.Windows.Forms namespace derives from the
Component class. This means that all controls, user controls and Forms use
this disposal model.

The Control class in ASP.NET provides its own implementation of IComponent,
but it doesn't conform to the component model disposal pattern above.
 

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