The context
I'm working with a Winforms application (.NET 3.5 SP1) which has the concept of workspaces, which can contain n number of panels. Each panel (derives from Panel
) has view:
.-----------------------. |Workspace | |.--------. .--------. | ||Panel1 | |Panel2 | | ||.-----. | |.-----. | | |||View1| | ||View2| | | ||'-----' | |'-----' | | |'--------' '--------' | '-----------------------'
All panels get added to the this.Controls
collection of the Workspace class (which derives from an UltraTabPageControl
, an Infragistics GUI control). Each view is added to the Controls
collection of their parent. So, when Dispose
is called on the Workspace, the panels and views automatically get disposed, which is completely expected and desired.
We have another concept called a ViewManager
. It keeps track of all the View
controls in the workspace, and is in charge of maintaining a single "master" view. Whenever a View
is created, it registers itself with this manager. This adds the View
to a list, and then runs some logic to determine the new "master" view and then calls a Synchronize()
method on each View.
The current design is that, whenever View.Dispose()
is called, it unregisters itself from the ViewManager
. This removes the View
from the list, and then runs corresponding logic that checks for a new master, out of the remaining views.
The twist
When we are closing an entire workspace, there is one special Panel
type that needs to be closed before other panels. So we have code in our Dispose
method that looks like this:
protected override void Dispose(bool disposing)
{
var theSpecialPanel = GetSpecialPanel();
if (theSpecialPanel != null)
{
theSpecialPanel.Dispose();
}
base.Dispose(disposing);
}
If we take out that code, then other panels may be disposed before theSpecialPanel
. This causes the logic that checks for a new master panel to be run, calls Synchronize()
on each View
including this special panel. This throws an
"InvalidComObjectException: COM object that has been separated from its underlying RCW cannot be used."
The question
Is this design is a code smell? Is it strange to enforce that a specific object gets disposed before others?