C# and destructors

K

Kimmo Laine

Hi,

lets say that i have class (C#) which will create some kind of communication
chanel, which is very expensive in terms of computer resources, and
therefore should be closed, when no longer needed. I have a method which
will create this chanel and a method which will close/release it.

My question is: is there a place where i can release this chanel if user
don´t call my release method? Can i write something like this:

public class MyClass {
// My communication chanel
private TheChannel m_Channel;

public MyClass() {
m_Channel = null;
}

~MyClass() {
if( m_Channel != null ) {
// Release channel
}
}

public void CreateChannel() { //... }
public void CloseChannel() { //... }
}

This method seems to work! But documentation says that "C# has no
destructor." It also says that is should use Dispose-method, like all the
..NET classes do, but it doesn't work!


Kimmo Laine
 
D

Dmitriy Lapshin [C# / .NET MVP]

Hi,

Please refer to the MSDN library on implementing the IDisposable interface
in components and the related design pattern.
 
M

Mark Broadbent

not quite true (not sure where you read that). C# has both a constructor and
destructer, and you have implemented the latter in your code.
Some classes already inherit and implement the IDisposible interface.
Otherwise the class must inherit it to allow you to make available and
implement the Dispose method. So in your code you would need...
public class MyClass: IDisposible
{..
Dispose()
{
//implementation here (clean up)
..
}
}

--

--

Br,
Mark Broadbent
mcdba , mcse+i
=============
 
J

Jon Skeet [C# MVP]

Dmitriy Lapshin said:
Please refer to the MSDN library on implementing the IDisposable interface
in components and the related design pattern.

Namely at:

http://tinyurl.com/2k6e

Note that your MyClass class probably *shouldn't* have a finalizer -
just a Dispose method. Your TheChannel class could have a finalizer
though.

I'm coming round to the idea that actually, all finalizers should be
something like:

#if DEBUG
~Foo
{
System.Windows.Forms.MessageBox.Show ("Dispose not called on Foo");
}
#endif

Finalizers shouldn't end up being used - if one gets called, that
usually means there's a bug in the program (assuming that Dispose
correctly suppresses finalization) and that bug may well bite you (at a
hard-to-detect time) if you don't fix it. So, instead of pretending
that the bug doesn't exist (by attempting to patch things up in the
finalizer), draw a developer's attention to the fact that he's got the
bug in the first place.

It's a bit of an aggressive approach, but it does appeal...
 
K

Kimmo Laine

Hi Dmitriy,

i did it but it doesn't work:

public class TestClass : IDisposable {
public TestClass() {
const string QNAME = @".\private$\Deltest";
MessageQueue mq = null;
if( MessageQueue.Exists( QNAME ) ) {
mq = new MessageQueue( QNAME );
} else {
mq = MessageQueue.Create( QNAME );
}
}

~TestClass() {
//Dispose( false );
}

protected virtual void Dispose( bool publicDispose ) {
if( publicDispose ) {
const string QNAME = @".\private$\Deltest";
if( MessageQueue.Exists( QNAME ) ) {
MessageQueue.Delete( QNAME );
}
}
}

public void Dispose() {
Dispose( true );
}
}

In this test, the message queue is not deleted.


Kimmo Laine






Dmitriy Lapshin said:
Hi,

Please refer to the MSDN library on implementing the IDisposable interface
in components and the related design pattern.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://www.x-unity.net/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Kimmo Laine said:
Hi,

lets say that i have class (C#) which will create some kind of communication
chanel, which is very expensive in terms of computer resources, and
therefore should be closed, when no longer needed. I have a method which
will create this chanel and a method which will close/release it.

My question is: is there a place where i can release this chanel if user
don´t call my release method? Can i write something like this:

public class MyClass {
// My communication chanel
private TheChannel m_Channel;

public MyClass() {
m_Channel = null;
}

~MyClass() {
if( m_Channel != null ) {
// Release channel
}
}

public void CreateChannel() { //... }
public void CloseChannel() { //... }
}

This method seems to work! But documentation says that "C# has no
destructor." It also says that is should use Dispose-method, like all the
.NET classes do, but it doesn't work!


Kimmo Laine
 
N

Niki Estner

what you read was correct: C# doesn't have destructors.
the destructor-syntax is a shortcut to implement the "finalize" method that
is called by the GC when the object gets cleaned up.
Unlike destructors, you cannot tell when a finalizer will be called, nor
what thread will call it, and finalizers make the GC less efficient - so you
should avoid them where you can (i.e. call SuppressFinalize in you
Dispose/Close/Release method).

And the "Dispose" pattern works fine if your class's clients call the
Dispose method.

Niki
 
D

Dilip Krishnan

Jon,
I totally agree with you on the fact that finalizers should seldom
be used, but your explanation thre threw me for a toss :)


that the bug doesn't exist (by attempting to patch things up in the
finalizer), draw a developer's attention to the fact that he's got the
bug in the first place.
<snip>

What do you mean when you say "pretend that the bug doesnt exist"?!!
 
J

Jon Skeet [C# MVP]

Dilip Krishnan said:
I totally agree with you on the fact that finalizers should seldom
be used, but your explanation thre threw me for a toss :)


<snip>

What do you mean when you say "pretend that the bug doesnt exist"?!!

If you fail to call Close/Dispose on a stream, you have a bug. However,
the framework will automatically close the stream for you when its
finalizer is called - so most of the time, it looks like you don't have
a bug. You still do, it's just not very obvious.
 
S

Scott English

For debugging, your suggestion is very good. However, one needs to consider
who will be using the object with the finalizer. If the object will be
ditributed in a compiled form for other programmers to consume, you should
still have the finalizer do cleanup.
 
S

Sami Vaaraniemi

Kimmo,

You need to call Dispose explicitly somewhere in your program. Did you do
this?

I also agree with Jon that pretty much the only thing you should do in the
finalizer is to verify that Dispose was called. If it was not called, then
you effectively have a bug and you should show an error message or do
something else to alert the programmer to the fact.

Regards,
Sami

Kimmo Laine said:
Hi Dmitriy,

i did it but it doesn't work:

public class TestClass : IDisposable {
public TestClass() {
const string QNAME = @".\private$\Deltest";
MessageQueue mq = null;
if( MessageQueue.Exists( QNAME ) ) {
mq = new MessageQueue( QNAME );
} else {
mq = MessageQueue.Create( QNAME );
}
}

~TestClass() {
//Dispose( false );
}

protected virtual void Dispose( bool publicDispose ) {
if( publicDispose ) {
const string QNAME = @".\private$\Deltest";
if( MessageQueue.Exists( QNAME ) ) {
MessageQueue.Delete( QNAME );
}
}
}

public void Dispose() {
Dispose( true );
}
}

In this test, the message queue is not deleted.


Kimmo Laine






Dmitriy Lapshin said:
Hi,

Please refer to the MSDN library on implementing the IDisposable interface
in components and the related design pattern.

--
Dmitriy Lapshin [C# / .NET MVP]
X-Unity Test Studio
http://www.x-unity.net/teststudio.aspx
Bring the power of unit testing to VS .NET IDE

Kimmo Laine said:
Hi,

lets say that i have class (C#) which will create some kind of communication
chanel, which is very expensive in terms of computer resources, and
therefore should be closed, when no longer needed. I have a method which
will create this chanel and a method which will close/release it.

My question is: is there a place where i can release this chanel if user
don´t call my release method? Can i write something like this:

public class MyClass {
// My communication chanel
private TheChannel m_Channel;

public MyClass() {
m_Channel = null;
}

~MyClass() {
if( m_Channel != null ) {
// Release channel
}
}

public void CreateChannel() { //... }
public void CloseChannel() { //... }
}

This method seems to work! But documentation says that "C# has no
destructor." It also says that is should use Dispose-method, like all the
.NET classes do, but it doesn't work!


Kimmo Laine
 
J

Jon Skeet [C# MVP]

Scott English said:
For debugging, your suggestion is very good. However, one needs to consider
who will be using the object with the finalizer. If the object will be
ditributed in a compiled form for other programmers to consume, you should
still have the finalizer do cleanup.

I'm not entirely convinced - 3rd party developers are in just as much
need of being told clearly that their program is broken as anyone else.

Getting the finalizer to do clean up just makes the problem harder to
spot - it goes from "broken always" to "broken for some indeterminate
length of time".

As I say, it's a bit of an aggressive stance, and I haven't actually
taken it yet in code I've written (not having had to include any
finalizers myself, that I can remember) but I think it has its merits.
 

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