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?