问题
I have following code that uses “using” block on TableHeaderCell
, LiteralControl
, HyperLink
and GridViewRow
(try..finally
). The code is working as indented. Is there any issue/pitfall in disposing the controls with “using” block as shown below? If yes, can you provide any msdn reference that shows details of the pitfall?
protected void grdTransactions_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e != null)
{
if (e.Row.RowType == DataControlRowType.Header)
{
GridViewRow newHeaderRow = null;
try
{
newHeaderRow = new GridViewRow(-1, -1, DataControlRowType.Header, DataControlRowState.Normal);
using (TableHeaderCell cellFirst = new TableHeaderCell())
{
cellFirst.ColumnSpan = 1;
cellFirst.Text = "FIRST";
newHeaderRow.Cells.Add(cellFirst);
}
using (TableHeaderCell cellAssociate = new TableHeaderCell())
{
GetTableCell(cellAssociate,"tableColGroupAssociate", 4, "associateHide", "Associate Transaction Info");
newHeaderRow.Cells.Add(cellAssociate);
}
newHeaderRow.Cells.Add(cellAssociate);
((GridView)sender).Controls[0].Controls.AddAt(0, newHeaderRow);
}
finally
{
if (newHeaderRow != null)
{
newHeaderRow.Dispose();
newHeaderRow = null;
}
}
}
}
}
Helper Method
private static void GetTableCell(TableHeaderCell cellAssociate, string cssClassName, int colSpan, string hideClassName, string displayName)
{
cellAssociate.ColumnSpan = colSpan;
cellAssociate.CssClass = cssClassName;
using (LiteralControl ltlText = new LiteralControl())
{
ltlText.Text = displayName;
cellAssociate.Controls.Add(ltlText);
}
using (HyperLink lnkHide = new HyperLink())
{
lnkHide.Text = SupportToolUIResource.HideLinkText;
lnkHide.CssClass = hideClassName;
lnkHide.Target = SupportToolUIResource.HideLinkTarget;
cellAssociate.Controls.Add(lnkHide);
}
}
Reference:
- Why would I need to call dispose on ASP.NET Controls?
回答1:
Even if you are "done" with the control, the page will access the control when it renders, so disposing them during construction doesn't make much sense. In one of your examples you are using one of the controls you just disposed, which also doesn't make sense.
Call Dispose when you are finished using the Control. 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.
The description of the Disposed event raised by the control also hints at the intended usage:
Occurs when a server control is released from memory, which is the last stage of the server control lifecycle when an ASP.NET page is requested.
Source: http://msdn.microsoft.com/en-us/library/system.web.ui.control.dispose.aspx
Source: http://msdn.microsoft.com/en-us/library/system.web.ui.control.disposed.aspx
See Also: https://stackoverflow.com/a/3151072/453277
So in theory:
- Build control tree.
- Page begins rendering.
- Page looks at controls added to tree.
- Controls have been disposed.
- Potential problems.
Here is the implementation of IDisposable
(from Control
). Note how it alters the container and event-related values.
public virtual void Dispose()
{
if (this.Site != null)
{
IContainer container = (IContainer)this.Site.GetService(typeof(IContainer));
if (container != null)
{
container.Remove(this);
EventHandler eventHandler = this.Events[Control.EventDisposed] as EventHandler;
if (eventHandler != null)
{
eventHandler(this, EventArgs.Empty);
}
}
}
if (this._occasionalFields != null)
{
this._occasionalFields.Dispose();
}
if (this._events != null)
{
this._events.Dispose();
this._events = null;
}
}
When to Dispose
That isn't to say you shouldn't dispose your resources; if a control needs to dispose resources, it is certainly free to do so. Perhaps a control accesses a database; I would wrap the database code inside a using
block inside the control.
In practicality, this style creates a large block of code for something which could be expressed more simply.
using (LiteralControl ltlText = new LiteralControl())
{
ltlText.Text = displayName;
cellAssociate.Controls.Add(ltlText);
}
// could become
cellAssociate.Controls.Add( new LiteralControl { Text = displayName } );
回答2:
Thanks to @Tim Medora for the explanation and the link Why would I need to call dispose on ASP.NET Controls? .
Some points of interest are:
- What we need to do is make sure that new controls are added is in the
Controls’ collection
so that it will be disposed when the Page is disposed. - Control objects implement the IDisposable interface. Each parent control can call Dispose on all of its children
- 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. (Assumeinvalid 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.
Conclusion
No need to use "using" block on webcontrols. Also, it may cause issues if "using" block is used on webcontrols.
来源:https://stackoverflow.com/questions/13448986/what-s-wrong-with-use-of-using-block-on-webcontrols