Is there a deconstructor?

  • Thread starter Thread starter Dom
  • Start date Start date
D

Dom

Is there a deconstructor in csharp? I'm thinking of a method that is
called up when the object is gone, for example, when you exit the
procedure it was constructed in. If so, is it reliable? I'm
concerned because, strictly speaking, you really don't know when an
object is deconstructed.

TIA,
Dom
 
* Dom said:
Is there a deconstructor in csharp? I'm thinking of a method that is
called up when the object is gone, for example, when you exit the
procedure it was constructed in. If so, is it reliable? I'm
concerned because, strictly speaking, you really don't know when an
object is deconstructed.

You can define a destructor (the syntax in C# is similar to C++). And,
as you probably suspected, it is called the instant the object is
destroyed. Indeed, you can't know when exactly this will be.

If you need explicit control over release of resources, read about the
IDisposable interface.

Regards,
Felix
 
Is there a deconstructor in csharp? I'm thinking of a method that is
called up when the object is gone, for example, when you exit the
procedure it was constructed in. If so, is it reliable? I'm
concerned because, strictly speaking, you really don't know when an
object is deconstructed.

No.

C# has finalizers, which is not a destructor (in the C++ sense).

And the only thing you need to know about finalizers are: don't
use them.

And you don't need it.

Manager memory get garbage collected.

Unmanaged resources should be handles via IDisposable
and Dispose (also see using statement).

Arne
 
* Arne Vajhøj said:
C# has finalizers, which is not a destructor (in the C++ sense).

Not exactly the same, but at least they are called at destruction, so
there is a similarity.
And the only thing you need to know about finalizers are: don't
use them.

And you don't need it.

At least, most of the time. There ARE patterns where they are useful
(otherwise they wouldn't be there), e.g. reference counting for shared
objects where you don't care if the container object lives a little
longer than absolutely needed.
Unmanaged resources should be handles via IDisposable
and Dispose (also see using statement).

Agreed. For explicit control over release of resources, that's the way
to go.

Regards,
Felix
 
* Arne Vajhøj said:
C# has finalizers, which is not a destructor (in the C++ sense).

Not exactly the same, but at least they are called at destruction, so
there is a similarity.
And the only thing you need to know about finalizers are: don't
use them.
And you don't need it.

At least, most of the time. There ARE patterns where they are useful
(otherwise they wouldn't be there), e.g. reference counting for shared
objects where you don't care if the container object lives a little
longer than absolutely needed.
Unmanaged resources should be handles via IDisposable
and Dispose (also see using statement).

Agreed. For explicit control over release of resources, that's the way
to go.

Regards,
Felix

--
 Felix Palmen       (Zirias)  + [PGP] Felix Palmen <[email protected]>
 web:  http://palmen-it.de/ |            http://palmen-it.de/pub.txt
 my open source projects:     |   Fingerprint: ED9B 62D0 BE39 32F9 2488
 http://palmen-it.de/?pg=pro +                5D0C 8177 9D80 5ECF F683

Let me ask this, then.

I have a class, "SQL", that, at construction, creates a connection to
a database. The class has a method called "Close", which closes the
connection. Typically, I would use it this way.

SQL s = new SQL();
s.Dothis()
s.Dothat()
s.Close()

The only problem is that I'm concerned that I, or someone else, may
write such a convoluted procedure that s.Close() does not get called,
and I would like to put that in the finalizer.

What is the best way to achieve my goal?
 
* Dom said:
I have a class, "SQL", that, at construction, creates a connection to
a database. The class has a method called "Close", which closes the
connection. Typically, I would use it this way.

SQL s = new SQL();
s.Dothis()
s.Dothat()
s.Close()

The only problem is that I'm concerned that I, or someone else, may
write such a convoluted procedure that s.Close() does not get called,
and I would like to put that in the finalizer.

What is the best way to achieve my goal?

Provide both, the finalizer and the IDisposable.Dispose() method. That
way, the connection will be closed eventually, even if your caller
doesn't bother to instantiate your class in a using block. When put in a
using block, the connection will be close as soon as possible.

Pattern:

class SQL : IDisposable
{
private void Close() { }

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

~SQL()
{
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// release managed objects, normally released by the default
// finalization
}
this.Close();
}
}

Then, prefer the following usage:
using (SQL s = new SQL())
{
s.DoSomething();
} // implicit close through IDisposable.Dispose

But even without a using block, the connection would be closed later
when the garbage collector reclaims your object.

Regards,
Felix
 
* Dom said:
I have a class, "SQL", that, at construction, creates a connection to
a database.  The class has a method called "Close", which closes the
connection.  Typically, I would use it this way.
SQL s = new SQL();
s.Dothis()
s.Dothat()
s.Close()
The only problem is that I'm concerned that I, or someone else, may
write such a convoluted procedure that s.Close() does not get called,
and I would like to put that in the finalizer.
What is the best way to achieve my goal?

Provide both, the finalizer and the IDisposable.Dispose() method. That
way, the connection will be closed eventually, even if your caller
doesn't bother to instantiate your class in a using block. When put in a
using block, the connection will be close as soon as possible.

Pattern:

class SQL : IDisposable
{
  private void Close() { }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }

  ~SQL()
  {
    Dispose(false);
  }

  protected virtual void Dispose(bool disposing)
  {
    if (disposing)
    {
      // release managed objects, normally released by the default
      // finalization
    }
    this.Close();
  }

}

Then, prefer the following usage:
using (SQL s = new SQL())
{
  s.DoSomething();

} // implicit close through IDisposable.Dispose

But even without a using block, the connection would be closed later
when the garbage collector reclaims your object.

Regards,
Felix

--
 Felix Palmen       (Zirias)  + [PGP] Felix Palmen <[email protected]>
 web:  http://palmen-it.de/ |            http://palmen-it.de/pub.txt
 my open source projects:     |   Fingerprint: ED9B 62D0 BE39 32F9 2488
 http://palmen-it.de/?pg=pro +                5D0C 8177 9D80 5ECF F683

Thanks Felix. I think that;s exaxctly what I want. But can you help
me with one small point. I see that your pattern is the one suggested
as MS, but it seems like this is a simpler pattern.

public void Dispose()
{
// Do nothing.
// Do not Suppress Finalize.
}

~SQL()
{
// Everything comes here.
// Either explicitly through a call to Dispose()
// or implicitly through "Using ()"
// or at Garbage Collection
// Managed Objects are released by default
// Handle unmanaged objects here
this.Close();
}

That seems easier, or am I missing something?
 
* Dom said:
Thanks Felix. I think that;s exaxctly what I want. But can you help
me with one small point. I see that your pattern is the one suggested
as MS, but it seems like this is a simpler pattern.

[Just a C# "destructor" (finalizer)]
That seems easier, or am I missing something?

Sure it "looks" easier, but it has two drawbacks:

- The connection will be closed some time later, and this could quite
easily be a significant amount of time (whenever the garbage collector
tried to release the object and scheduled a finalizer thread).
- You suffer a performance overhead because the garbage collector cannot
release the object in the first attempt when it finds a finalizer that
has to be called. Instead, it has to create a thread (which is costly)
and after the finalizer was run, there will be a second attempt to
release the object.

Implementing IDisposable, you can avoid that by creating your object in
a using-block. When the block is left, Dispose() is called
automatically. Alternatively, you could call Dispose() yourself, but the
using-block is safer because it'll catch any way you might leave it (a
return statement, an exception, ...).

As a fallback, you still provide a finalizer, so if your caller misses
the using-block or the call to Dispose(), it gets called at
finalization. To avoid the overhead described above, you suppress
finalization if Dispose() was correctly called.

I'd suggest you also add a boolean member variable "disposed" that
serves as a flag for a disposed object. Most method calls will be
invalid after the object was disposed, so those method's implementations
should start with a line
| if (disposed) throw new ObjectDisposedException(
| "Object was already disposed.");

You can also use this flag to ignore double calls to Dispose().

Regards,
Felix
 
* Dom said:
Thanks Felix.  I think that;s exaxctly what I want.  But can you help
me with one small point.  I see that your pattern is the one suggested
as MS, but it seems like this is a simpler pattern.

[Just a C# "destructor" (finalizer)]
That seems easier, or am I missing something?

Sure it "looks" easier, but it has two drawbacks:

- The connection will be closed some time later, and this could quite
  easily be a significant amount of time (whenever the garbage collector
  tried to release the object and scheduled a finalizer thread).
- You suffer a performance overhead because the garbage collector cannot
  release the object in the first attempt when it finds a finalizer that
  has to be called. Instead, it has to create a thread (which is costly)
  and after the finalizer was run, there will be a second attempt to
  release the object.

Implementing IDisposable, you can avoid that by creating your object in
a using-block. When the block is left, Dispose() is called
automatically. Alternatively, you could call Dispose() yourself, but the
using-block is safer because it'll catch any way you might leave it (a
return statement, an exception, ...).

As a fallback, you still provide a finalizer, so if your caller misses
the using-block or the call to Dispose(), it gets called at
finalization. To avoid the overhead described above, you suppress
finalization if Dispose() was correctly called.

I'd suggest you also add a boolean member variable "disposed" that
serves as a flag for a disposed object. Most method calls will be
invalid after the object was disposed, so those method's implementations
should start with a line
| if (disposed) throw new ObjectDisposedException(
|       "Object was already disposed.");

You can also use this flag to ignore double calls to Dispose().

Regards,
Felix

--
 Felix Palmen       (Zirias)  + [PGP] Felix Palmen <[email protected]>
 web:  http://palmen-it.de/ |            http://palmen-it.de/pub.txt
 my open source projects:     |   Fingerprint: ED9B 62D0 BE39 32F9 2488
 http://palmen-it.de/?pg=pro +                5D0C 8177 9D80 5ECF F683

Makes sense. Thanks alot.
 
At least, most of the time. There ARE patterns where they are useful
(otherwise they wouldn't be there), e.g. reference counting for shared
objects where you don't care if the container object lives a little
longer than absolutely needed.

It can be a lot longer. Or it could never be called at all.

And reference counting is not the .NET way.

Arne
 
Let me ask this, then.

I have a class, "SQL", that, at construction, creates a connection to
a database. The class has a method called "Close", which closes the
connection. Typically, I would use it this way.

SQL s = new SQL();
s.Dothis()
s.Dothat()
s.Close()

The only problem is that I'm concerned that I, or someone else, may
write such a convoluted procedure that s.Close() does not get called,
and I would like to put that in the finalizer.

That is not good.

Use IDispoable and Dispose.

Arne
 
Provide both, the finalizer and the IDisposable.Dispose() method. That
way, the connection will be closed eventually, even if your caller
doesn't bother to instantiate your class in a using block. When put in a
using block, the connection will be close as soon as possible.

Pattern:

class SQL : IDisposable
{
private void Close() { }

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

~SQL()
{
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// release managed objects, normally released by the default
// finalization
}
this.Close();
}
}

Then, prefer the following usage:
using (SQL s = new SQL())
{
s.DoSomething();
} // implicit close through IDisposable.Dispose

But even without a using block, the connection would be closed later
when the garbage collector reclaims your object.

That is a frequently used pattern and recommended by
Microsoft.

I would find it very tempting instead to do something
in the finalizer to indicate that there is a problem
in the way the class is used instead of doing something
that may silently fix the problem but may not prevent
it from crashing the app later.

Arne
 
* Dom said:
I have a class, "SQL", that, at construction, creates a connection to
a database. The class has a method called "Close", which closes the
connection. Typically, I would use it this way.
SQL s = new SQL();
s.Dothis()
s.Dothat()
s.Close()
The only problem is that I'm concerned that I, or someone else, may
write such a convoluted procedure that s.Close() does not get called,
and I would like to put that in the finalizer.
What is the best way to achieve my goal?

Provide both, the finalizer and the IDisposable.Dispose() method. That
way, the connection will be closed eventually, even if your caller
doesn't bother to instantiate your class in a using block. When put in a
using block, the connection will be close as soon as possible.

Pattern:

class SQL : IDisposable
{
private void Close() { }

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

~SQL()
{
Dispose(false);
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// release managed objects, normally released by the default
// finalization
}
this.Close();
}

}

Then, prefer the following usage:
using (SQL s = new SQL())
{
s.DoSomething();

} // implicit close through IDisposable.Dispose

But even without a using block, the connection would be closed later
when the garbage collector reclaims your object.

Regards,
Felix

--
Felix Palmen (Zirias) + [PGP] Felix Palmen<[email protected]>
web: http://palmen-it.de/ | http://palmen-it.de/pub.txt
my open source projects: | Fingerprint: ED9B 62D0 BE39 32F9 2488
http://palmen-it.de/?pg=pro + 5D0C 8177 9D80 5ECF F683

Thanks Felix. I think that;s exaxctly what I want. But can you help
me with one small point. I see that your pattern is the one suggested
as MS, but it seems like this is a simpler pattern.

public void Dispose()
{
// Do nothing.
// Do not Suppress Finalize.
}

~SQL()
{
// Everything comes here.
// Either explicitly through a call to Dispose()
// or implicitly through "Using ()"
// or at Garbage Collection
// Managed Objects are released by default
// Handle unmanaged objects here
this.Close();
}

That seems easier, or am I missing something?

Assuming that the SQL class contains one or more
SqlConnection objects, then this will work on a
system with little memory causing frequent garbage
collections, but on a systems with lots of memory it
may run out of database connections and crash the
application.

Good candidate for something that will pass QA and
crash in production.

So ....

Arne
 
* Arne Vajhøj said:
And reference counting is not the .NET way.

It's a pattern that is not MUCH needed in the presence of a garbage
collector, but there are still use cases. Try not to be dogmatic, that's
stupid because it sometimes prevents finding the best solution.

Regards,
Felix
 
* Arne Vajhøj said:
I would find it very tempting instead to do something
in the finalizer to indicate that there is a problem
in the way the class is used instead of doing something
that may silently fix the problem but may not prevent
it from crashing the app later.

Given the limited possibilities inside a finalizer (e.g. throwing an
exception would be totally pointless), doing the necessary cleanup
anyway seems the only sensible thing to do. You could write "Hey, you
forgot to dispose me" to some log file and hope the programmer ever
reads it :)

Regards,
Felix
 
Back
Top