Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object doesn't get garbage collected

I think this is a C# beginner question, but I can't seem to find a correct solution.

I have a ClassOne object, which defines an event. I create a ClassTwo object, which is considered as a black box, which means I don't know whether it will register to any event or not. ClassTwo constructor registers to the event of ClassOne. The problem comes, when ClassTwo object goes out of scope. The garbage collector never deletes this object, because it never deregistered the event.

So I have two questions:

  1. Is there a way for ClassTwo object to know, when it goes out of scope? For an old C++ programmer this would be in the destructor, but with C# this doesn't work.

  2. Is there a debug tool which helps me to find such objects?

Here is a sample code to reproduce the issue:

    public partial class MainWindow : Window
{
    static public ClassOne classOne = new ClassOne();
    public MainWindow()
    {
        InitializeComponent();
        ClassTwo classtwo = new ClassTwo();
    }

    private void buttonTest_Click(object sender, RoutedEventArgs e)
    {
        GC.Collect();
    }
}
public class ClassOne
{
    public ClassOne()
    {
        Trace.WriteLine(this + " constructor");
    }

    ~ClassOne()
    {
        Trace.WriteLine(this + " destructor");
    }

    public delegate void UpdateFunc(object sender, EventArgs args);
    public event UpdateFunc OnUpdate;

}
public class ClassTwo
{
    public ClassTwo()
    {
        Trace.WriteLine(this + " constructor");
        MainWindow.classOne.OnUpdate += new ClassOne.UpdateFunc(classOne_OnUpdate);
    }

    void classOne_OnUpdate(object sender, EventArgs args)
    {
        throw new NotImplementedException();
    }

    ~ClassTwo()
    {
        Trace.WriteLine(this + " destructor");
    }
}
like image 439
MTR Avatar asked Jul 25 '11 14:07

MTR


2 Answers

I would implement IDisposable on an object like this and unregister from the event in the Dispose method. You would use your object like this:

using(var two = new ClassTwo(classOne))
{
    // Do something with two
}
// object can now be garbage collected.

If the caller fails to call Dispose, you are out of luck.

like image 156
Daniel Hilgarth Avatar answered Sep 23 '22 02:09

Daniel Hilgarth


  1. Not unless it implements IDisposable and the caller cooperates by calling Dispose correctly. (Of course, why wouldn't the caller cooperate?)

  2. Not that I've of. :( I think your best bet is to implement IDisposable and unregister on Dispose.

like image 21
user541686 Avatar answered Sep 26 '22 02:09

user541686