Remove handler when usercontrol is disposing

2019-07-28 06:28发布

问题:

Which one is the right one?

This one:

protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        this.ctlRBContent1_GetBuildName -= _ctlBottom.GetBuildName;
        components.Dispose();
    }
    base.Dispose(disposing);
}

OR

This one:

~ ctlRemoteBuildContent1()
{
    this.ctlRBContent1_GetBuildName -= _ctlBottom.GetBuildName;
}

I tried to toggle this 2 functions. When I did UserControl disposing, it didn't jump into the toggle line :/

回答1:

If you clean up in a destructor, there's no guarantee as to when the destructor will be run. Objects with a destructor also require more work for the garbage collector to handle. It's preferable therefore to implement IDisposable, which is your first example.

Note that your code snippet does not fully implement the recommended IDisposable pattern. Please see this article for a good and complete explanation:

http://www.csharphelp.com/2010/02/c-garbage-collecting-destructors-versus-dispose/

In your code snippet, if for some reason components is null, you would not remove the event handler. The null check for components should only be done to protect the components.Dispose() call.

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        this.ctlRBContent1_GetBuildName -= _ctlBottom.GetBuildName;
        if (components != null)
        {
            components.Dispose();
        }
    }
    base.Dispose(disposing);
}


回答2:

The second bit of code is called by the finalizer, which means you won't be able to tell when this is called (depends on when the garbage collector runs). Ideally you want to free your resources as soon as possible, typically in a Dispose(). So use the dispose pattern here.

Why do you want to unsubscribe that event here? What does it contain?



回答3:

Which one is the right one?

A slightly obnoxious answer is "both" ;-) ...

Ideally you want the tidying up to happen in the Dispose method so it can be performed as soon as possible, but in some situations it's important to also have the tidy up code called from the destructor as a back-up in case an object gets used without being disposed (...I guess it depends on how likely you think this could be!?)

The dispose pattern (mentioned in the other answers) provides a way of implementing this without code duplication between the dispose and destructor, and with the GC.SupressFinalize makes sure the object's garbage collection doesn't get held up unnecessarily if the tidy up has been done.