9

Hello,

I have been trying to learn c# from dotnet tutorial and they gave this code which supposed to trigger garbage collector and in turn call the Destructor of the class. however when I run the same code, I get result of Constructor only and not the Destructor.

using System;
namespace DestructorExample
{
    class DestructorDemo
    {
        public DestructorDemo()
        {
            Console.WriteLine("Constructor Object Created");
        }
        ~DestructorDemo()
        {
            string type = GetType().Name;
            Console.WriteLine($"Object {type} is Destroyed");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            DestructorDemo obj1 = new DestructorDemo();
            DestructorDemo obj2 = new DestructorDemo();

            //Making obj1 for Garbage Collection
            obj1 = null;
            GC.Collect();
            Console.ReadKey();
        }
    }
}

here is the code, if you know please tell me why it's not working

top 10 comments
sorted by: hot top controversial new old
[-] copygirl@lemmy.blahaj.zone 5 points 5 days ago* (last edited 5 days ago)

My recommendations would be:

  • Do not rely on GC.Collect() in any real program code. Just let the GC do its thing.
  • If you need guarantees about when the destructor (or equivalent) is called, use the dispose pattern and use a using statement or declaration explicitly so Dispose gets called as soon as possible.
class DestructorDemo : IDisposable
{
    public string Name { get; set; }
    public DestructorDemo(string name)
    {
        Name = name;
        Console.WriteLine($"demo object {Name} constructed");
    }
    public void Dispose()
    {
        Console.WriteLine($"demo object {Name} disposed");
    }
}

using var obj1 = new DestructorDemo("obj1");

using (var obj2 = new DestructorDemo("obj2"))
{
    Console.WriteLine("Press key to dispose 'obj2'");
    Console.ReadKey();
    // obj2 goes out of scope at the end of the block
    // this will automatically call `.Dispose()` on it
}

Console.WriteLine("Press key to dispose 'obj1' and exit");
Console.ReadKey();

// obj1 goes out of scope here

Note that this code is just to showcase the using keyword (in relation to IDisposable). If you want to implement the disposable pattern properly you should look at the help article I linked. Such as making sure that Dispose is called even if the object is naturally garbage collected, that is if you forget to use using. (I also didn't check the validity of the code but it should get the idea across.)

Unless the purpose is to get a destructor to trigger only. This is the most correct answer. This pattern is very widely used and can prevent crashes. The using block is a try{}finally{} behind the scenes but without the catch it just throws and could be caught higher up the stack on accident. When I was a fresh grad this pattern saved my dumb ass when I unintentionally would catch the exceptions somewhere else, but hey it didn't crash.

[-] JakenVeina@midwest.social 3 points 5 days ago

Relevant article: https://ericlippert.com/2015/05/18/when-everything-you-know-is-wrong-part-one/

Long story short, whoever wrote that tutorial is wrong: you cannot guarantee invocation of finalizers. My guess would be it's old and maybe used to work, but the inner workings of the GC have changed since then.

[-] Mihies@programming.dev 4 points 6 days ago

OTOH gc might decide not to collect it immediately since it's in a static method, try this instead

DestructorDemo? obj1 = new DestructorDemo();
//Making obj1 for Garbage Collection
obj1 = null;
for (int i = 0; i < 10; i++)
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    obj1 = new DestructorDemo();
}

You'll see destructor in action.

[-] airbreather@lemmy.world 1 points 5 days ago* (last edited 5 days ago)

Conventionally (as much as the term could apply to this unconventional situation) the pattern I've seen has been to do a second GC.Collect(); right after the GC.WaitForPendingFinalizers();

Otherwise yes, without running it (I'm far enough away from a PC right now) I am highly confident that this is the answer (edit to add: minus the details of the descriptions of why this is the case, which conflict with my understanding of how this stuff works).

[-] MotoAsh@piefed.social 2 points 6 days ago* (last edited 6 days ago)

Far more familiar with Java since I've mostly used that the last decade, but two questions come to mind...

  1. Does the console object buffer output? I know you're waiting for a key, but sometimes buffers do weird things like not flushing when you expect.
  2. Is GetType failing silently? I'm not familiar with the innards of C# any more, but in rare occasions in other languages, errors/exceptions get silently swallowed. Usually it's with funky code that amounts to a logical error and not a true magically swallowed exception, but...

At least GC.Collect() is a blocking collect, but perhaps there could also be funky shenanigans happening? I'd also think it'd collect obj1, but it is still in the same scope it was created in. Maybe there could also be some funkyness there with objects only getting picked up if they're out of scope or similar?

I'd imagine most of the above would be really easy to test if you can get a debugger to step through. If it doesn't hit at all, something odd is happening with flagging the objects for collection I'd think. If it hits but errors, easy peasy. If it hits and executes fine but doesn't show, maybe as others suggested, use a different function rather than something from Console or something?

[-] 6nk06@sh.itjust.works 2 points 6 days ago* (last edited 6 days ago)

Some ideas:

It's been a long time since I used Java and C# but you were not supposed to write destructors, or "close objects" improperly by setting a null value, or calling collect explicitly.

Also you're blocking the application with ReadKey to trick the terminal into keeping the window open. That could prevent the GC from working at this specific step because the main function is not over yet. Configure the IDE instead to keep the terminal open, and remove ReadKey.

Calling collect is only a piece of advice to the GC, it could wait after you press the key but you wouldn't see it if the terminal closes too fast.

[-] Mihies@programming.dev 1 points 6 days ago

GC.Collect runs in a different thread and it is not blocked by waiting on terminal. And calling Collect is not just a piece of advice, it starts collection. And yes, usually one does not call Collect unless it knows why (there are cases it makes sense), but setting reference to null doesn't hurt (but doesn't help probably). As per destructors, those are for freeing unmanaged resources only.

[-] MotoAsh@piefed.social 1 points 6 days ago

(not OP) I had a similar thought but it turns out GC.Collect() is a blocking collect.

Whether that means it will actually destroy the objects fully before it returns... I'd think so based on the description, but I've definitely seen worse lies in documentation!

[-] Mihies@programming.dev 2 points 6 days ago

Try with Trace.WriteLine instead of Console.

this post was submitted on 16 Dec 2025
9 points (100.0% liked)

C Sharp

1749 readers
2 users here now

A community about the C# programming language

Getting started

Useful resources

IDEs and code editors

Tools

Rules

Related communities

founded 2 years ago
MODERATORS