10

Say, I have my own C# class defined as such:

public class MyClass
{
    public MyClass()
    {
        //Do the work
    }
    ~MyClass()
    {
        //Destructor
    }
}

And then I create an instance of my class from an ASP.NET project, as such:

if(true)
{
    MyClass c = new MyClass();
    //Do some work with 'c'

    //Shouldn't destructor for 'c' be called here?
}

//Continue on

I'd expect the destructor to be called at the end of the if scope but it never is called. What am I missing?

AgentFire
  • 8,944
  • 8
  • 43
  • 90
c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • 5
    It will be called when the garbage collector is working, and you can't know when this will happen. – JustAnotherUserYouMayKnow Jun 24 '13 at 07:41
  • So, what is the purpose of destructors in C# then? – c00000fd Jun 24 '13 at 07:41
  • same as other language's destructor does, free up memory & resources. – Raptor Jun 24 '13 at 07:42
  • @c00000fd Releasing system resources correctly. You can't assume the GC to know how those are to be released. – Nolonar Jun 24 '13 at 07:42
  • Well, I guess I spent too long with C/C++. In my view destructors are called at the end of the scope where the variable they represent is declared in. – c00000fd Jun 24 '13 at 07:43
  • 1
    If your class uses unmanaged resources you can use the destructor to release those properly. If it doesn't use managed resources a destructor is rarely ever necessary... Additionally, C# works a little different than usual C++ -> you lose the reference to an object, when the reference goes out of scope when you `new`ed an object. Eventually the GC will destroy the object on the heap. Automatic variables are destroyed when they go out of scope. – bash.d Jun 24 '13 at 07:44
  • @c00000fd In C/C++ you still need to call `delete` on objects that were created with `new`. In C#, the GC does that for you. – Nolonar Jun 24 '13 at 07:47
  • @Nolonar: Yes, indeed. In a very old fashioned C. Nowadays I'd use the RAII concept: http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization – c00000fd Jun 24 '13 at 07:49

3 Answers3

8

The equivalent to a C++ destructor is IDisposable and the Dispose() method, often used in a using block.

See http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

What you are calling a destructor is better known as a Finalizer.

Here's how you would use IDisposable. Note that Dispose() is not automatically called; the best you can do is to use using which will cause Dispose() to be called, even if there is an exception within the using block before it reaches the end.

public class MyClass: IDisposable
{
    public MyClass()
    {
        //Do the work
    }

    public void Dispose()
    {
        // Clean stuff up.
    }
}

Then you could use it like this:

using (MyClass c = new MyClass())
{
    // Do some work with 'C'
    // Even if there is an exception, c.Dispose() will be called before
    // the 'using' block is exited.
}

You can call .Dispose() explicitly yourself if you need to. The only point of using is to automate calling .Dispose() when execution leaves the using block for any reason.

See here for more info: http://msdn.microsoft.com/en-us/library/yh598w02%28v=vs.110%29.aspx

Basically, the using block above is equivalent to:

MyClass c = new MyClass();

try
{
    // Do some work with 'C'
}

finally
{
    if (c != null)
        ((IDisposable)c).Dispose();
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • Oh, I see. I need to have `using` block, right? Because `Dispose` method is not called without it. – c00000fd Jun 24 '13 at 08:05
  • @c00000fd That's correct, although you could call `c.Dispose()` explicitly yourself if you need to. The purpose of `using` is to handle automatically calling it. I'll add some more info to the answer in a sec. – Matthew Watson Jun 24 '13 at 08:10
  • why does the finally block have ((IDisposable)c).Dispose(); instead of just c.Dispose(); . Aren't they both the same thing? – user20358 Jan 29 '15 at 10:26
  • 1
    @user20358 It's for when the `Dispose()` method has been implemented using `explicit interface implementation`. In such cases, you have to cast to call it. – Matthew Watson Jan 30 '15 at 10:58
4

There is no way you can control a timing or make a guess on when actually destructor of the object will be called. It's all up to the Garbage Collector.

The only think you can be sure, in this case, that at the moment you leave that scope the object c becomes unreachable (I assume there are no global references to that instance inside the scope), so the instance c is intended to be identified and removed by Garbage Collector when time comes.

Crab Bucket
  • 6,219
  • 8
  • 38
  • 73
Tigran
  • 61,654
  • 8
  • 86
  • 123
  • OK. Thank you. It explains it. Although it makes destructors almost completely useless in C#. – c00000fd Jun 24 '13 at 07:58
  • @c00000fd: will you may think about it like a special event (kind of it) that raised by CLR when your instance is collected, so it *may* have some use, but surely not in most cases. – Tigran Jun 24 '13 at 08:03
2

It is up to the garbage collector as to when an object is freed up. However you can force an object to be freed up by calling Finalize. or GC.Collect which will force the garbage collector to take action.

Darren
  • 68,902
  • 24
  • 138
  • 144
  • Well, the whole point of using destructors (in a language I'm familiar with -- C/C++) is to have them called implicitly. If I have to call them explicitly, then I can just be OK with a simple method. So I guess the whole concept of RAII is out of the window in C# too, hah? – c00000fd Jun 24 '13 at 07:46
  • @c00000fd - C# is a managed language - let the CLR take care of memory allocation for you, it will finalize the object when it deems appropriate. However you can force it via `GC.Collect` like I mention in my answer. – Darren Jun 24 '13 at 07:48
  • That still doesn't force the garbage collector. Just puts it on a higher priority thread. – nunespascal Jun 24 '13 at 07:48
  • 1
    @nunespascal - according to MSDN it Forces an immediate garbage collection of all generations. – Darren Jun 24 '13 at 07:49
  • The reason I need the destructor to be called on that spot is because I need the object (named mutex) to be released on that particular spot. I can't wait for the garbage collector to come in... – c00000fd Jun 24 '13 at 07:50
  • 1
    @c00000fd The equivalent to a C++ destructor is `IDisposable` and the `Dispose()` method, often used in a `using` block. See http://msdn.microsoft.com/en-us/library/system.idisposable.aspx What you are calling a destructor is better known as a `Finalizer`, and it's quite different from a C++ destructor. – Matthew Watson Jun 24 '13 at 07:58
  • @MatthewWatson: Hmm. Very nice. So how would I add it to my class. Simply deriving it from `IDisposable` and providing `public void Dispose(){}` doesn't seem to work. The `Dispose()` is not called at the end of the if() scope. – c00000fd Jun 24 '13 at 08:03