Link to home
Start Free TrialLog in
Avatar of DouglasHolt
DouglasHoltFlag for United States of America

asked on

Destructors in C#

Ok, this may be a dumb question, but I'm looking for anything that resembles a C++ destructor in C#.

I know that the garbage collector is used to free up resources, etc.  However, destructors can be quite useful for much more than deleting memory or freeing up handles, etc.

Many times (in C++) I will use destructors to trigger events when an object goes out of scope.  I actually use some objects just for their destructor.  I want to have that capability in C#.  Is it possible?  I don't care how I get there, as long as I can reliably run some chunk of code based on the event of an object going out of scope.

Any help is appreciated!

Douglas Holt
douglasholt@cox.net
Avatar of Timbo87
Timbo87

Destructors are possible in C#, although they can't be explicitly called (I believe they can be in C++, but I don't do much development in it). They are syntacticly identical to C++.

public class A
{
     ~A()
     {
          Console.WriteLine("Running the A destructor.");
     }
}

Under the hood, this is translated to override the Finalize method of the base class Object.

There's an in-depth article which goes into some of the IL here:
http://www.c-sharpcorner.com/Code/2002/June/UnderstandingDestructors.asp
Avatar of DouglasHolt

ASKER

I understand roughly how the Garbage Collector works.  And I know that destructors are called by the GC.  What I need is something that is reliably called upon the event of an object falling out of scope.

One thought is this:  An object's ref count drops to zero when it falls out of scope.  Is there an event or other mechanism that can be tapped into when the ref count drops to zero?

Remember, I'm not using this like a destructor to free up resources, I need it for timing, synchronization, etc.  So it has to happen just like a C++ destructor.  I don't care what this mechanism is called, or how it's used, and I know it must exist or the Ref Count could never drop to zero.
There is more to this question than meets the eye.

First of all, the only methods that are automatically called when an object falls out of scope is either the destructor or the Finalize() method if it is specified.  These however can't be completely relied upon because they are only called when the GC does a pass.  And then it is not even guaranteed!

What you can do is to implement the IDisposable interface, and use the Dispose() Method to call anything that you want.  This method must however be called explicitly.

In this Dispose() method, you must call the GC.SuppressFinalize() Method to stop the object from being finalized, because when an object falls out of scope it is put on the finalization que, and this que still has a reference to the object, which defeats the purpose in this case.

What you can do then, is to manually count the references to the object in the Dispose() method, and when the count == 0 you have your required state.

You can also still add a destructor or a Finalize() method to destroy the object if it is not done explicitly by a user of your class.

public YourClass : IDisposable {
   ~YourClass() {
      //Put your destructor code here
   }

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

   protected void Dispose(bool disposing) {
      if (disposing) {
         GC.SuppressFinalize(this);
         //Dispose of your managed objects if disposing
      }
      //Dispose of your external resources here
      ...
   }
   ...
}

I hope this makes any sense
But the whole point is to eliminate the need to explicitly call something like Dispose.  So, this completely defeats my purpose.
Well, like I said: the only methods that are called automatically are the destructor or the Finalize() method, but then you have to rely on the GC to delete the reference.  And you can't use this for timing or synchronization, as you can't be sure when the GC is going to delete it.
So, the bottom line is that C# is not able to do what C++ destructors do, no matter what, period, end of story?
I wouldn't go so far as to say that it is impossible.  It's just highly unlikely that it would work the same way because of the GC.  In C++, you deleted the objects yourself, so it would go out of scope immediately.  In C# you have to wait for the GC.

You can call the GC explicitly to schedule a GC pass, but you still can't be sure that it will delete the required object.

I am not 100% sure what you are allowed to do with unmanaged code in C#, but you might want to look into that and see if you can then make it happen exactly as in C++.
I have to stay with managed code for my client.

By calling the GC to make a pass, that would be as much work if not more than calling an explicit Dispose, or Close method.

The solution I'm looking for cannot be related to the GC.  I know what the GC does, and that's not what I'm after.  I'm after the event that must get called to decrement the object's ref count immediately as it goes out of scope.  But I'm betting that it's not an "event" that can be tapped into.  My guess is that it's hardwired in the generated code, and nothing can access it.  But I'm all ears if there is any other potential solution!!!
ASKER CERTIFIED SOLUTION
Avatar of msdixon
msdixon

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You are an absolute genius!  Yes, this is exactly what I want.  It's not nearly as pretty as C++, but it does work.  I set breakpoints, and it hits them just exactly as I hoped!  Thank you, thank you, thank you!!!  Yes, you get the points!
msdixon,

Excellent, now I just have one more piece to my puzzle.  Could I get you to take a look at my other question: "How can I store a ref of an object within a class for later use?" in this section?  Here's the link:

https://www.experts-exchange.com/questions/21207416/How-can-I-store-a-ref-of-an-object-within-a-class-for-later-use.html

You have no idea how happy this makes me.  I've been cursing C#'s lack of destructors since I first was forced to use it over C++.  I'll be dancing today!