Tim
Tim

Reputation: 8921

detaching anonymous listeners from events in C# and garbage collection

Let's say I have a class called Dialog that extends Form. There's a textbox on the dialog and an OK button, and when the user clicks OK, the textbox value is returned via an event:

public class Dialog: Form
{
    public delegate void onDialogValueReturned(object sender, DialogEventArgs e);
    public event onDialogValueReturned DialogValueReturned;
 .
 .
 .

  OKButton.Click += (sender, evt) =>
        {
            DialogEventArgs e = new DialogEventArgs();
            e.Value =myTextBox.Text;                
            DialogValueReturned(this, e);
            this.Close();
        };

In my calling form, I'm instantiating a dialog in a local method:

  private void Foo()
  {
        Dialog D = new Dialog("blah blah");
        D.DialogValueReturned += (dialog, evt) =>
            {

               //do something with evt.Value

            };


        D.ShowDialog();
   }

This dialog might be instantiated dozens or even hundreds of times by the user during the course of the day.

Does the garbage collector automatically clean up everything relating to the dialog instance when scope leaves the private method, including all of the plumbing for the anonymous listener?

Thanks

Upvotes: 4

Views: 581

Answers (2)

npclaudiu
npclaudiu

Reputation: 2441

The anonymous function will result in a member function having its name generated automatically by the compiler. The compiler-generated name will contain characters that are illegal in C# to ensure that you cannot name another member in your class with the same name. Other than that, it will behave absolutely identical as normal methods bound to an event and thus, all the resources involved will be garbage collected.

And as a design note, since you are interested in a value returned from the dialog, I would advise against using an event to notify that the dialog window was closed. Instead, you could wrap your code in a static method for example, in which you open the dialog, wait for the event loop until the dialog is closed and read the input from the user, returning the input data in a format that is more suitable for further processing. This would require you to open a modal window. Here is an example:

public class MyDialog : Form
{
    // We can make the constructor private, as this class is instantiated only
    // in the Show method.
    private MyDialog()
    {
    }

    // ...

    public class ReturnValue
    {
        public string Foo { get; set; }
        // ...
    }

    public static ReturnValue ShowModal(/* any params, if required */)
    {
        ReturnValue result = new ReturnValue();
        MyDialog dialog = new MyDialog();

        if(DialogResult.OK == dialog.ShowDialog(null))
        {
            // We can access private members like txtFoo since we are within the class.
            result.Foo = dialog.txtFoo.Text;

            // ...
        }

        return result;
    }
}

Upvotes: 0

sga101
sga101

Reputation: 1904

The publisher of an event retains a strong reference to each subscriber. If the publisher is longer lived than the subscribers, then the subscribers will be pinned in memory while the publisher is present.

In your example, the publisher only exists within the scope of your private method, so both the dialog and the handler will be garbage collected at some point after the method returns.

I would recommend complying with the dot net framework guidelines for publishing an event, which suggests using a protected virtual method to invoke the events.

Upvotes: 2

Related Questions