Why would I need to call dispose on ASP.NET Contro

2019-01-15 14:00发布

问题:

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?

回答1:

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.