I'm doing some ASP.NET development in VS and have just found an interesting little code suggestion (I think they come from coderush but I could be wrong).
Whenever I'm creating controls it tells me that I should be using a "using" statement for them. I'm a bit confused as to what is going on here though. with the using my code looks something like:
using (HtmlTableRow tableRow = new HtmlTableRow())
{
tableRow.Attributes.Add("class", isOddRow ? "OddRow" : "EvenRow");
listingTable.Rows.Add(tableRow);
addCell(tableRow, row, "issueId");
addCell(tableRow, row, "Title");
addCell(tableRow, row, "Type");
addCell(tableRow, row, "Summary");
}
So I am expecting that at the end of the using statement it will call dispose on the tableRow. However, the docs in MSDN library says:
The Dispose method leaves the Control
in an unusable state. After calling
this method, you must release all
references to the control so the
memory it was occupying can be
reclaimed by garbage collection.
So I would expect that I now have an unusable object in my control structure so it would break or not render or something. However, everything seems to work just fine.
So what I'm wondering is why are all controls disposable? Is it just because some of them will be and making them all disposable means that one call to dispose at the top level can then be passed down to all child controls recursively?
I think I'd understand if not for the fact that the docs explicitly say that disposing of a control makes it unusable... Are the docs just wrong?
You shouldn't actually do this. What you need to do is make sure that listingTable is in the Controls
collection so that it will be disposed when the Page is disposed. The listingTable object is then responsible for properly disposing all of its children.
Which is why all Control
objects implement the IDisposable interface. That way each parent control can call Dispose
on all of its children without first having to test/cast each one. Each control is individually responsible for determining whether it actually has anything that needs to be cleaned up when its Dispose
method is called.
The docs are not wrong. Any properly-written object that implements IDisposable and has state data that is actually cleaned up during the dispose process should throw an ObjectDisposedException if any of its public/protected/internal properties or methods are accessed after it has been disposed. (Assume invalid state after Dispose
has been called.) Some types will ignore this rule if they don't actually have anything to clean up, and don't have to worry about invalid state.
The reason you're getting a suggestion to wrap it in a using
block is because the analyzer doesn't realize that listingTable
will dispose its Rows
collection, which will dispose each of the row objects that have been added to it. Also, if an exception is thrown between HtmlTableRow tableRow = new HtmlTableRow()
and listingTable.Rows.Add(tableRow)
, the HtmlTableRow object will be 'orphaned' and not be in any other object's IDisposable
hierarchy. Code Analysis wants you to use a try/finally block to immediately dispose of the HtmlTableRow
if this happens.