Read interface IList.Count once rather than per iteration (#9962)
This commit is contained in:
parent
3e0afe4029
commit
19c9010c2f
|
|
@ -139,9 +139,12 @@ namespace Microsoft.AspNetCore.Routing.Patterns
|
||||||
throw new ArgumentNullException(nameof(name));
|
throw new ArgumentNullException(nameof(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < Parameters.Count; i++)
|
var parameters = Parameters;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var parametersCount = parameters.Count;
|
||||||
|
for (var i = 0; i < parametersCount; i++)
|
||||||
{
|
{
|
||||||
var parameter = Parameters[i];
|
var parameter = parameters[i];
|
||||||
if (string.Equals(parameter.Name, name, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(parameter.Name, name, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return parameter;
|
return parameter;
|
||||||
|
|
|
||||||
|
|
@ -521,16 +521,20 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < _pattern.PathSegments.Count; i++)
|
var segments = _pattern.PathSegments;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var segmentsCount = segments.Count;
|
||||||
|
for (var i = 0; i < segmentsCount; i++)
|
||||||
{
|
{
|
||||||
Debug.Assert(context.BufferState == SegmentState.Beginning);
|
Debug.Assert(context.BufferState == SegmentState.Beginning);
|
||||||
Debug.Assert(context.UriState == SegmentState.Beginning);
|
Debug.Assert(context.UriState == SegmentState.Beginning);
|
||||||
|
|
||||||
var segment = _pattern.PathSegments[i];
|
var parts = segments[i].Parts;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
for (var j = 0; j < segment.Parts.Count; j++)
|
var partsCount = parts.Count;
|
||||||
|
for (var j = 0; j < partsCount; j++)
|
||||||
{
|
{
|
||||||
var part = segment.Parts[j];
|
var part = parts[j];
|
||||||
|
|
||||||
if (part is RoutePatternLiteralPart literalPart)
|
if (part is RoutePatternLiteralPart literalPart)
|
||||||
{
|
{
|
||||||
|
|
@ -581,7 +585,7 @@ namespace Microsoft.AspNetCore.Routing.Template
|
||||||
// for format, so we remove '.' and generate 5.
|
// for format, so we remove '.' and generate 5.
|
||||||
if (!context.Accept(converted, parameterPart.EncodeSlashes))
|
if (!context.Accept(converted, parameterPart.EncodeSlashes))
|
||||||
{
|
{
|
||||||
if (j != 0 && parameterPart.IsOptional && (separatorPart = segment.Parts[j - 1] as RoutePatternSeparatorPart) != null)
|
if (j != 0 && parameterPart.IsOptional && (separatorPart = parts[j - 1] as RoutePatternSeparatorPart) != null)
|
||||||
{
|
{
|
||||||
context.Remove(separatorPart.Content);
|
context.Remove(separatorPart.Content);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,14 +113,20 @@ namespace Microsoft.AspNetCore.Routing.Tree
|
||||||
{
|
{
|
||||||
// Any entries in node.Matches have had all their required values satisfied, so add them
|
// Any entries in node.Matches have had all their required values satisfied, so add them
|
||||||
// to the results.
|
// to the results.
|
||||||
for (var i = 0; i < node.Matches.Count; i++)
|
var matches = node.Matches;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var matchesCount = matches.Count;
|
||||||
|
for (var i = 0; i < matchesCount; i++)
|
||||||
{
|
{
|
||||||
results.Add(new OutboundMatchResult(node.Matches[i], isFallbackPath));
|
results.Add(new OutboundMatchResult(matches[i], isFallbackPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < node.Criteria.Count; i++)
|
var criteria = node.Criteria;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var criteriaCount = criteria.Count;
|
||||||
|
for (var i = 0; i < criteriaCount; i++)
|
||||||
{
|
{
|
||||||
var criterion = node.Criteria[i];
|
var criterion = criteria[i];
|
||||||
var key = criterion.Key;
|
var key = criterion.Key;
|
||||||
|
|
||||||
if (values.TryGetValue(key, out var value))
|
if (values.TryGetValue(key, out var value))
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,12 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
||||||
|
|
||||||
if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
|
if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
|
||||||
{
|
{
|
||||||
// Perf: Avoid allocations
|
var results = context.Results;
|
||||||
for (var i = 0; i < context.Results.Count; i++)
|
// Perf: Avoid allocating enumerator and read interface .Count once rather than per iteration
|
||||||
|
var resultsCount = results.Count;
|
||||||
|
for (var i = 0; i < resultsCount; i++)
|
||||||
{
|
{
|
||||||
ProvideFilter(context, context.Results[i]);
|
ProvideFilter(context, results[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -249,15 +249,18 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
isMainPage);
|
isMainPage);
|
||||||
Dictionary<string, string> expanderValues = null;
|
Dictionary<string, string> expanderValues = null;
|
||||||
|
|
||||||
if (_options.ViewLocationExpanders.Count > 0)
|
var expanders = _options.ViewLocationExpanders;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var expandersCount = expanders.Count;
|
||||||
|
if (expandersCount > 0)
|
||||||
{
|
{
|
||||||
expanderValues = new Dictionary<string, string>(StringComparer.Ordinal);
|
expanderValues = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||||
expanderContext.Values = expanderValues;
|
expanderContext.Values = expanderValues;
|
||||||
|
|
||||||
// Perf: Avoid allocations
|
// Perf: Avoid allocations
|
||||||
for (var i = 0; i < _options.ViewLocationExpanders.Count; i++)
|
for (var i = 0; i < expandersCount; i++)
|
||||||
{
|
{
|
||||||
_options.ViewLocationExpanders[i].PopulateValues(expanderContext);
|
expanders[i].PopulateValues(expanderContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,9 +353,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
{
|
{
|
||||||
var viewLocations = GetViewLocationFormats(expanderContext);
|
var viewLocations = GetViewLocationFormats(expanderContext);
|
||||||
|
|
||||||
for (var i = 0; i < _options.ViewLocationExpanders.Count; i++)
|
var expanders = _options.ViewLocationExpanders;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var expandersCount = expanders.Count;
|
||||||
|
for (var i = 0; i < expandersCount; i++)
|
||||||
{
|
{
|
||||||
viewLocations = _options.ViewLocationExpanders[i].ExpandViewLocations(expanderContext, viewLocations);
|
viewLocations = expanders[i].ExpandViewLocations(expanderContext, viewLocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewLocationCacheResult cacheResult = null;
|
ViewLocationCacheResult cacheResult = null;
|
||||||
|
|
@ -404,9 +410,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
||||||
var viewDescriptor = factoryResult.ViewDescriptor;
|
var viewDescriptor = factoryResult.ViewDescriptor;
|
||||||
if (viewDescriptor?.ExpirationTokens != null)
|
if (viewDescriptor?.ExpirationTokens != null)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < viewDescriptor.ExpirationTokens.Count; i++)
|
var viewExpirationTokens = viewDescriptor.ExpirationTokens;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var viewExpirationTokensCount = viewExpirationTokens.Count;
|
||||||
|
for (var i = 0; i < viewExpirationTokensCount; i++)
|
||||||
{
|
{
|
||||||
expirationTokens.Add(viewDescriptor.ExpirationTokens[i]);
|
expirationTokens.Add(viewExpirationTokens[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,9 +156,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||||
throw new ArgumentNullException(nameof(output));
|
throw new ArgumentNullException(nameof(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < output.Attributes.Count; i++)
|
var attributes = output.Attributes;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var attributesCount = attributes.Count;
|
||||||
|
for (var i = 0; i < attributesCount; i++)
|
||||||
{
|
{
|
||||||
var attribute = output.Attributes[i];
|
var attribute = attributes[i];
|
||||||
if (!string.Equals(attribute.Name, attributeName, StringComparison.OrdinalIgnoreCase))
|
if (!string.Equals(attribute.Name, attributeName, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -170,7 +173,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||||
string resolvedUrl;
|
string resolvedUrl;
|
||||||
if (TryResolveUrl(stringValue, resolvedUrl: out resolvedUrl))
|
if (TryResolveUrl(stringValue, resolvedUrl: out resolvedUrl))
|
||||||
{
|
{
|
||||||
output.Attributes[i] = new TagHelperAttribute(
|
attributes[i] = new TagHelperAttribute(
|
||||||
attribute.Name,
|
attribute.Name,
|
||||||
resolvedUrl,
|
resolvedUrl,
|
||||||
attribute.ValueStyle);
|
attribute.ValueStyle);
|
||||||
|
|
@ -199,7 +202,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||||
IHtmlContent resolvedUrl;
|
IHtmlContent resolvedUrl;
|
||||||
if (TryResolveUrl(stringValue, resolvedUrl: out resolvedUrl))
|
if (TryResolveUrl(stringValue, resolvedUrl: out resolvedUrl))
|
||||||
{
|
{
|
||||||
output.Attributes[i] = new TagHelperAttribute(
|
attributes[i] = new TagHelperAttribute(
|
||||||
attribute.Name,
|
attribute.Name,
|
||||||
resolvedUrl,
|
resolvedUrl,
|
||||||
attribute.ValueStyle);
|
attribute.ValueStyle);
|
||||||
|
|
@ -207,7 +210,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.TagHelpers
|
||||||
else if (htmlString == null)
|
else if (htmlString == null)
|
||||||
{
|
{
|
||||||
// Not a ~/ URL. Just avoid re-encoding the attribute value later.
|
// Not a ~/ URL. Just avoid re-encoding the attribute value later.
|
||||||
output.Attributes[i] = new TagHelperAttribute(
|
attributes[i] = new TagHelperAttribute(
|
||||||
attribute.Name,
|
attribute.Name,
|
||||||
new HtmlString(stringValue),
|
new HtmlString(stringValue),
|
||||||
attribute.ValueStyle);
|
attribute.ValueStyle);
|
||||||
|
|
|
||||||
|
|
@ -44,13 +44,20 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
}
|
}
|
||||||
|
|
||||||
var foundResult = false;
|
var foundResult = false;
|
||||||
result = default(TMode);
|
result = default;
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator
|
||||||
for (var i = 0; i < modeInfos.Count; i++)
|
var modeInfosCount = modeInfos.Count;
|
||||||
|
var allAttributes = context.AllAttributes;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var allAttributesCount = allAttributes.Count;
|
||||||
|
for (var i = 0; i < modeInfosCount; i++)
|
||||||
{
|
{
|
||||||
var modeInfo = modeInfos[i];
|
var modeInfo = modeInfos[i];
|
||||||
if (!HasMissingAttributes(context, modeInfo.Attributes) &&
|
var requiredAttributes = modeInfo.Attributes;
|
||||||
|
// If there are fewer attributes present than required, one or more of them must be missing.
|
||||||
|
if (allAttributesCount >= requiredAttributes.Length &&
|
||||||
|
!HasMissingAttributes(allAttributes, requiredAttributes) &&
|
||||||
compare(result, modeInfo.Mode) <= 0)
|
compare(result, modeInfo.Mode) <= 0)
|
||||||
{
|
{
|
||||||
foundResult = true;
|
foundResult = true;
|
||||||
|
|
@ -61,19 +68,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
return foundResult;
|
return foundResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasMissingAttributes(TagHelperContext context, string[] requiredAttributes)
|
private static bool HasMissingAttributes(ReadOnlyTagHelperAttributeList allAttributes, string[] requiredAttributes)
|
||||||
{
|
{
|
||||||
if (context.AllAttributes.Count < requiredAttributes.Length)
|
|
||||||
{
|
|
||||||
// If there are fewer attributes present than required, one or more of them must be missing.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for all attribute values
|
// Check for all attribute values
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator
|
||||||
for (var i = 0; i < requiredAttributes.Length; i++)
|
for (var i = 0; i < requiredAttributes.Length; i++)
|
||||||
{
|
{
|
||||||
if (!context.AllAttributes.TryGetAttribute(requiredAttributes[i], out var attribute))
|
if (!allAttributes.TryGetAttribute(requiredAttributes[i], out var attribute))
|
||||||
{
|
{
|
||||||
// Missing attribute.
|
// Missing attribute.
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -381,8 +381,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
builder.AppendHtml(", \"");
|
builder.AppendHtml(", \"");
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator and read interface .Count once rather than per iteration
|
||||||
for (var i = 0; i < attributes.Count; i++)
|
var attributesCount = attributes.Count;
|
||||||
|
for (var i = 0; i < attributesCount; i++)
|
||||||
{
|
{
|
||||||
var attribute = attributes[i];
|
var attribute = attributes[i];
|
||||||
if (string.Equals(attribute.Name, HrefAttributeName, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(attribute.Name, HrefAttributeName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
|
@ -440,8 +441,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
builder.AppendHtml("[");
|
builder.AppendHtml("[");
|
||||||
var firstAdded = false;
|
var firstAdded = false;
|
||||||
// Perf: Avoid allocating enumerator
|
|
||||||
for (var i = 0; i < fallbackHrefs.Count; i++)
|
// Perf: Avoid allocating enumerator and read interface .Count once rather than per iteration
|
||||||
|
var fallbackHrefsCount = fallbackHrefs.Count;
|
||||||
|
for (var i = 0; i < fallbackHrefsCount; i++)
|
||||||
{
|
{
|
||||||
if (firstAdded)
|
if (firstAdded)
|
||||||
{
|
{
|
||||||
|
|
@ -498,8 +501,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
var addHref = true;
|
var addHref = true;
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator and read interface .Count once rather than per iteration
|
||||||
for (var i = 0; i < attributes.Count; i++)
|
var attributesCount = attributes.Count;
|
||||||
|
for (var i = 0; i < attributesCount; i++)
|
||||||
{
|
{
|
||||||
var attribute = attributes[i];
|
var attribute = attributes[i];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -331,8 +331,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
var addSrc = true;
|
var addSrc = true;
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator and read interface .Count once rather than per iteration
|
||||||
for (var i = 0; i < attributes.Count; i++)
|
var attributesCount = attributes.Count;
|
||||||
|
for (var i = 0; i < attributesCount; i++)
|
||||||
{
|
{
|
||||||
var attribute = attributes[i];
|
var attribute = attributes[i];
|
||||||
if (!attribute.Name.Equals(SrcAttributeName, StringComparison.OrdinalIgnoreCase))
|
if (!attribute.Name.Equals(SrcAttributeName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
|
@ -434,8 +435,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
var addSrc = true;
|
var addSrc = true;
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator and read interface .Count once rather than per iteration
|
||||||
for (var i = 0; i < attributes.Count; i++)
|
var attributesCount = attributes.Count;
|
||||||
|
for (var i = 0; i < attributesCount; i++)
|
||||||
{
|
{
|
||||||
var attribute = attributes[i];
|
var attribute = attributes[i];
|
||||||
if (!attribute.Name.Equals(SrcAttributeName, StringComparison.OrdinalIgnoreCase))
|
if (!attribute.Name.Equals(SrcAttributeName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
|
|
||||||
|
|
@ -321,13 +321,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
TagHelperOutput tagHelperOutput,
|
TagHelperOutput tagHelperOutput,
|
||||||
TagHelperContext context)
|
TagHelperContext context)
|
||||||
{
|
{
|
||||||
var existingAttribute = context.AllAttributes[allAttributeIndex];
|
var allAttributes = context.AllAttributes;
|
||||||
|
var existingAttribute = allAttributes[allAttributeIndex];
|
||||||
|
|
||||||
// Move backwards through context.AllAttributes from the provided index until we find a familiar attribute
|
// Move backwards through context.AllAttributes from the provided index until we find a familiar attribute
|
||||||
// in tagHelperOutput where we can insert the copied value after the familiar one.
|
// in tagHelperOutput where we can insert the copied value after the familiar one.
|
||||||
for (var i = allAttributeIndex - 1; i >= 0; i--)
|
for (var i = allAttributeIndex - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var previousName = context.AllAttributes[i].Name;
|
var previousName = allAttributes[i].Name;
|
||||||
var index = IndexOfFirstMatch(previousName, tagHelperOutput.Attributes);
|
var index = IndexOfFirstMatch(previousName, tagHelperOutput.Attributes);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
|
|
@ -336,11 +337,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var allAttributesCount = allAttributes.Count;
|
||||||
// Move forward through context.AllAttributes from the provided index until we find a familiar attribute in
|
// Move forward through context.AllAttributes from the provided index until we find a familiar attribute in
|
||||||
// tagHelperOutput where we can insert the copied value.
|
// tagHelperOutput where we can insert the copied value.
|
||||||
for (var i = allAttributeIndex + 1; i < context.AllAttributes.Count; i++)
|
for (var i = allAttributeIndex + 1; i < allAttributesCount; i++)
|
||||||
{
|
{
|
||||||
var nextName = context.AllAttributes[i].Name;
|
var nextName = allAttributes[i].Name;
|
||||||
var index = IndexOfFirstMatch(nextName, tagHelperOutput.Attributes);
|
var index = IndexOfFirstMatch(nextName, tagHelperOutput.Attributes);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
|
|
@ -355,7 +358,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
|
|
||||||
private static int IndexOfFirstMatch(string name, TagHelperAttributeList attributes)
|
private static int IndexOfFirstMatch(string name, TagHelperAttributeList attributes)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < attributes.Count; i++)
|
// Read interface .Count once rather than per iteration
|
||||||
|
var attributesCount = attributes.Count;
|
||||||
|
for (var i = 0; i < attributesCount; i++)
|
||||||
{
|
{
|
||||||
if (string.Equals(name, attributes[i].Name, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(name, attributes[i].Name, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,6 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
|
||||||
public partial class TagHelperRunner
|
public partial class TagHelperRunner
|
||||||
{
|
{
|
||||||
public TagHelperRunner() { }
|
public TagHelperRunner() { }
|
||||||
[System.Diagnostics.DebuggerStepThroughAttribute]
|
|
||||||
public System.Threading.Tasks.Task RunAsync(Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext executionContext) { throw null; }
|
public System.Threading.Tasks.Task RunAsync(Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext executionContext) { throw null; }
|
||||||
}
|
}
|
||||||
public partial class TagHelperScopeManager
|
public partial class TagHelperScopeManager
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>Resulting <see cref="TagHelperOutput"/> from processing all of the
|
/// <returns>Resulting <see cref="TagHelperOutput"/> from processing all of the
|
||||||
/// <paramref name="executionContext"/>'s <see cref="ITagHelper"/>s.</returns>
|
/// <paramref name="executionContext"/>'s <see cref="ITagHelper"/>s.</returns>
|
||||||
public async Task RunAsync(TagHelperExecutionContext executionContext)
|
public Task RunAsync(TagHelperExecutionContext executionContext)
|
||||||
{
|
{
|
||||||
if (executionContext == null)
|
if (executionContext == null)
|
||||||
{
|
{
|
||||||
|
|
@ -28,19 +28,40 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagHelperContext = executionContext.Context;
|
var tagHelperContext = executionContext.Context;
|
||||||
|
var tagHelpers = executionContext.TagHelpers;
|
||||||
|
OrderTagHelpers(tagHelpers);
|
||||||
|
|
||||||
OrderTagHelpers(executionContext.TagHelpers);
|
// Read interface .Count once rather than per iteration
|
||||||
|
var count = tagHelpers.Count;
|
||||||
for (var i = 0; i < executionContext.TagHelpers.Count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
executionContext.TagHelpers[i].Init(tagHelperContext);
|
tagHelpers[i].Init(tagHelperContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagHelperOutput = executionContext.Output;
|
var tagHelperOutput = executionContext.Output;
|
||||||
|
|
||||||
for (var i = 0; i < executionContext.TagHelpers.Count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
await executionContext.TagHelpers[i].ProcessAsync(tagHelperContext, tagHelperOutput);
|
var task = tagHelpers[i].ProcessAsync(tagHelperContext, tagHelperOutput);
|
||||||
|
if (!task.IsCompletedSuccessfully)
|
||||||
|
{
|
||||||
|
return Awaited(task, executionContext, i + 1, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
static async Task Awaited(Task task, TagHelperExecutionContext executionContext, int i, int count)
|
||||||
|
{
|
||||||
|
await task;
|
||||||
|
|
||||||
|
var tagHelpers = executionContext.TagHelpers;
|
||||||
|
var tagHelperOutput = executionContext.Output;
|
||||||
|
var tagHelperContext = executionContext.Context;
|
||||||
|
for (; i < count; i++)
|
||||||
|
{
|
||||||
|
await tagHelpers[i].ProcessAsync(tagHelperContext, tagHelperOutput);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,14 +69,16 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
|
||||||
{
|
{
|
||||||
// Using bubble-sort here due to its simplicity. It'd be an extreme corner case to ever have more than 3 or
|
// Using bubble-sort here due to its simplicity. It'd be an extreme corner case to ever have more than 3 or
|
||||||
// 4 tag helpers simultaneously.
|
// 4 tag helpers simultaneously.
|
||||||
ITagHelper temp = null;
|
|
||||||
for (var i = 0; i < tagHelpers.Count; i++)
|
// Read interface .Count once rather than per iteration
|
||||||
|
var count = tagHelpers.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
for (var j = i + 1; j < tagHelpers.Count; j++)
|
for (var j = i + 1; j < count; j++)
|
||||||
{
|
{
|
||||||
if (tagHelpers[j].Order < tagHelpers[i].Order)
|
if (tagHelpers[j].Order < tagHelpers[i].Order)
|
||||||
{
|
{
|
||||||
temp = tagHelpers[i];
|
var temp = tagHelpers[i];
|
||||||
tagHelpers[i] = tagHelpers[j];
|
tagHelpers[i] = tagHelpers[j];
|
||||||
tagHelpers[j] = temp;
|
tagHelpers[j] = temp;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,15 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator
|
||||||
for (var i = 0; i < Items.Count; i++)
|
var items = Items;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var itemsCount = items.Count;
|
||||||
|
for (var i = 0; i < itemsCount; i++)
|
||||||
{
|
{
|
||||||
if (NameEquals(name, Items[i]))
|
var attribute = items[i];
|
||||||
|
if (NameEquals(name, attribute))
|
||||||
{
|
{
|
||||||
return Items[i];
|
return attribute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,16 +130,20 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator
|
||||||
List<TagHelperAttribute> matchedAttributes = null;
|
List<TagHelperAttribute> matchedAttributes = null;
|
||||||
for (var i = 0; i < Items.Count; i++)
|
var items = Items;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var itemsCount = items.Count;
|
||||||
|
for (var i = 0; i < itemsCount; i++)
|
||||||
{
|
{
|
||||||
if (NameEquals(name, Items[i]))
|
var attribute = items[i];
|
||||||
|
if (NameEquals(name, attribute))
|
||||||
{
|
{
|
||||||
if (matchedAttributes == null)
|
if (matchedAttributes == null)
|
||||||
{
|
{
|
||||||
matchedAttributes = new List<TagHelperAttribute>();
|
matchedAttributes = new List<TagHelperAttribute>();
|
||||||
}
|
}
|
||||||
|
|
||||||
matchedAttributes.Add(Items[i]);
|
matchedAttributes.Add(attribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
attributes = matchedAttributes ?? EmptyList;
|
attributes = matchedAttributes ?? EmptyList;
|
||||||
|
|
@ -158,9 +166,12 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||||
throw new ArgumentNullException(nameof(name));
|
throw new ArgumentNullException(nameof(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < Items.Count; i++)
|
var items = Items;
|
||||||
|
// Read interface .Count once rather than per iteration
|
||||||
|
var itemsCount = items.Count;
|
||||||
|
for (var i = 0; i < itemsCount; i++)
|
||||||
{
|
{
|
||||||
if (NameEquals(name, Items[i]))
|
if (NameEquals(name, items[i]))
|
||||||
{
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -305,8 +305,9 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||||
destination.AppendHtml("<");
|
destination.AppendHtml("<");
|
||||||
destination.AppendHtml(TagName);
|
destination.AppendHtml(TagName);
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator, cache .Count as it goes via interface
|
||||||
for (var i = 0; i < Attributes.Count; i++)
|
var count = Attributes.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var attribute = Attributes[i];
|
var attribute = Attributes[i];
|
||||||
destination.AppendHtml(" ");
|
destination.AppendHtml(" ");
|
||||||
|
|
@ -356,8 +357,9 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||||
destination.AppendHtml("<");
|
destination.AppendHtml("<");
|
||||||
destination.AppendHtml(TagName);
|
destination.AppendHtml(TagName);
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator, cache .Count as it goes via interface
|
||||||
for (var i = 0; i < Attributes.Count; i++)
|
var count = Attributes.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var attribute = Attributes[i];
|
var attribute = Attributes[i];
|
||||||
destination.AppendHtml(" ");
|
destination.AppendHtml(" ");
|
||||||
|
|
@ -416,8 +418,9 @@ namespace Microsoft.AspNetCore.Razor.TagHelpers
|
||||||
writer.Write("<");
|
writer.Write("<");
|
||||||
writer.Write(TagName);
|
writer.Write(TagName);
|
||||||
|
|
||||||
// Perf: Avoid allocating enumerator
|
// Perf: Avoid allocating enumerator, cache .Count as it goes via interface
|
||||||
for (var i = 0; i < Attributes.Count; i++)
|
var count = Attributes.Count;
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var attribute = Attributes[i];
|
var attribute = Attributes[i];
|
||||||
writer.Write(" ");
|
writer.Write(" ");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue