Lazily initialize `TagHelperOutput`s `Content` properties.

- Added backing fields to each of the content properties and added null propagation checks throughout the class.

#358
This commit is contained in:
N. Taylor Mullen 2015-11-12 17:11:59 -08:00
parent bdf869c3d5
commit e8327eeec7
1 changed files with 88 additions and 17 deletions

View File

@ -15,6 +15,12 @@ namespace Microsoft.AspNet.Razor.TagHelpers
public class TagHelperOutput : IHtmlContent public class TagHelperOutput : IHtmlContent
{ {
private readonly Func<bool, Task<TagHelperContent>> _getChildContentAsync; private readonly Func<bool, Task<TagHelperContent>> _getChildContentAsync;
private TagHelperContent _preElement;
private TagHelperContent _preContent;
private TagHelperContent _content;
private TagHelperContent _postContent;
private TagHelperContent _postElement;
private bool _wasSuppressOutputCalled;
// Internal for testing // Internal for testing
internal TagHelperOutput(string tagName) internal TagHelperOutput(string tagName)
@ -64,32 +70,96 @@ namespace Microsoft.AspNet.Razor.TagHelpers
/// Content that precedes the HTML element. /// Content that precedes the HTML element.
/// </summary> /// </summary>
/// <remarks>Value is rendered before the HTML element.</remarks> /// <remarks>Value is rendered before the HTML element.</remarks>
public TagHelperContent PreElement { get; } = new DefaultTagHelperContent(); public TagHelperContent PreElement
{
get
{
if (_preElement == null)
{
_preElement = new DefaultTagHelperContent();
}
return _preElement;
}
}
/// <summary> /// <summary>
/// The HTML element's pre content. /// The HTML element's pre content.
/// </summary> /// </summary>
/// <remarks>Value is prepended to the <see cref="ITagHelper"/>'s final output.</remarks> /// <remarks>Value is prepended to the <see cref="ITagHelper"/>'s final output.</remarks>
public TagHelperContent PreContent { get; } = new DefaultTagHelperContent(); public TagHelperContent PreContent
{
get
{
if (_preContent == null)
{
_preContent = new DefaultTagHelperContent();
}
return _preContent;
}
}
/// <summary> /// <summary>
/// The HTML element's main content. /// Get or set the HTML element's main content.
/// </summary> /// </summary>
/// <remarks>Value occurs in the <see cref="ITagHelper"/>'s final output after <see cref="PreContent"/> and /// <remarks>Value occurs in the <see cref="ITagHelper"/>'s final output after <see cref="PreContent"/> and
/// before <see cref="PostContent"/></remarks> /// before <see cref="PostContent"/></remarks>
public TagHelperContent Content { get; } = new DefaultTagHelperContent(); public TagHelperContent Content
{
get
{
if (_content == null)
{
_content = new DefaultTagHelperContent();
}
return _content;
}
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_content = value;
}
}
/// <summary> /// <summary>
/// The HTML element's post content. /// The HTML element's post content.
/// </summary> /// </summary>
/// <remarks>Value is appended to the <see cref="ITagHelper"/>'s final output.</remarks> /// <remarks>Value is appended to the <see cref="ITagHelper"/>'s final output.</remarks>
public TagHelperContent PostContent { get; } = new DefaultTagHelperContent(); public TagHelperContent PostContent
{
get
{
if (_postContent == null)
{
_postContent = new DefaultTagHelperContent();
}
return _postContent;
}
}
/// <summary> /// <summary>
/// Content that follows the HTML element. /// Content that follows the HTML element.
/// </summary> /// </summary>
/// <remarks>Value is rendered after the HTML element.</remarks> /// <remarks>Value is rendered after the HTML element.</remarks>
public TagHelperContent PostElement { get; } = new DefaultTagHelperContent(); public TagHelperContent PostElement
{
get
{
if (_postElement == null)
{
_postElement = new DefaultTagHelperContent();
}
return _postElement;
}
}
/// <summary> /// <summary>
/// <c>true</c> if <see cref="Content"/> has been set, <c>false</c> otherwise. /// <c>true</c> if <see cref="Content"/> has been set, <c>false</c> otherwise.
@ -98,7 +168,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
{ {
get get
{ {
return Content.IsModified; return _wasSuppressOutputCalled || _content?.IsModified == true;
} }
} }
@ -127,11 +197,12 @@ namespace Microsoft.AspNet.Razor.TagHelpers
public void SuppressOutput() public void SuppressOutput()
{ {
TagName = null; TagName = null;
PreElement.Clear(); _wasSuppressOutputCalled = true;
PreContent.Clear(); _preElement?.Clear();
Content.Clear(); _preContent?.Clear();
PostContent.Clear(); _content?.Clear();
PostElement.Clear(); _postContent?.Clear();
_postElement?.Clear();
} }
/// <summary> /// <summary>
@ -163,7 +234,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
throw new ArgumentNullException(nameof(writer)); throw new ArgumentNullException(nameof(writer));
} }
PreElement.WriteTo(writer, encoder); _preElement?.WriteTo(writer, encoder);
var isTagNameNullOrWhitespace = string.IsNullOrWhiteSpace(TagName); var isTagNameNullOrWhitespace = string.IsNullOrWhiteSpace(TagName);
@ -218,11 +289,11 @@ namespace Microsoft.AspNet.Razor.TagHelpers
if (isTagNameNullOrWhitespace || TagMode == TagMode.StartTagAndEndTag) if (isTagNameNullOrWhitespace || TagMode == TagMode.StartTagAndEndTag)
{ {
PreContent.WriteTo(writer, encoder); _preContent?.WriteTo(writer, encoder);
Content.WriteTo(writer, encoder); _content?.WriteTo(writer, encoder);
PostContent.WriteTo(writer, encoder); _postContent?.WriteTo(writer, encoder);
} }
if (!isTagNameNullOrWhitespace && TagMode == TagMode.StartTagAndEndTag) if (!isTagNameNullOrWhitespace && TagMode == TagMode.StartTagAndEndTag)
@ -232,7 +303,7 @@ namespace Microsoft.AspNet.Razor.TagHelpers
writer.Write(">"); writer.Write(">");
} }
PostElement.WriteTo(writer, encoder); _postElement?.WriteTo(writer, encoder);
} }
} }
} }