private bool TryCachePreallocatedVariableName(TagHelperAttributeKey key, out string preAllocatedAttributeVariableName) { if (!_preAllocatedAttributes.TryGetValue(key, out preAllocatedAttributeVariableName)) { preAllocatedAttributeVariableName = _preAllocatedAttributeVariablePrefix + _preAllocatedAttributes.Count; _preAllocatedAttributes[key] = preAllocatedAttributeVariableName; return(true); } return(false); }
private void PreAllocateTagHelperAttributes(TagHelperChunk chunk) { var boundAttributes = new HashSet <string>(StringComparer.OrdinalIgnoreCase); for (var i = 0; i < chunk.Attributes.Count; i++) { var attribute = chunk.Attributes[i]; var associatedAttributeDescriptors = chunk.Descriptors.SelectMany(descriptor => descriptor.Attributes) .Where(attributeDescriptor => attributeDescriptor.IsNameMatch(attribute.Name)); // If there's no descriptors associated or is a repeated attribute with same name as a bound attribute, // it is considered as an unbound attribute. var isUnBoundAttribute = !associatedAttributeDescriptors.Any() || !boundAttributes.Add(attribute.Name); // Perf: We will preallocate TagHelperAttribute for unbound attributes and simple bound string valued attributes. if (isUnBoundAttribute || CanPreallocateBoundAttribute(associatedAttributeDescriptors, attribute)) { string preAllocatedAttributeVariableName = null; if (attribute.ValueStyle == HtmlAttributeValueStyle.Minimized) { Debug.Assert(attribute.Value == null); var preAllocatedAttributeKey = new TagHelperAttributeKey( attribute.Name, value: null, unBoundAttribute: isUnBoundAttribute, valueStyle: attribute.ValueStyle); if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName)) { Writer .Write("private static readonly global::") .Write(_tagHelperContext.TagHelperAttributeTypeName) .Write(" ") .Write(preAllocatedAttributeVariableName) .Write(" = ") .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName) .WriteStringLiteral(attribute.Name) .WriteEndMethodInvocation(); } } else { Debug.Assert(attribute.Value != null); string plainText; if (CSharpTagHelperCodeRenderer.TryGetPlainTextValue(attribute.Value, out plainText)) { var preAllocatedAttributeKey = new TagHelperAttributeKey(attribute.Name, plainText, isUnBoundAttribute, attribute.ValueStyle); if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName)) { Writer .Write("private static readonly global::") .Write(_tagHelperContext.TagHelperAttributeTypeName) .Write(" ") .Write(preAllocatedAttributeVariableName) .Write(" = ") .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName) .WriteStringLiteral(attribute.Name) .WriteParameterSeparator(); if (isUnBoundAttribute) { // For unbound attributes, we need to create HtmlString. Writer .WriteStartNewObject("global::" + _tagHelperContext.EncodedHtmlStringTypeName) .WriteStringLiteral(plainText) .WriteEndMethodInvocation(endLine: false); } else { Writer.WriteStringLiteral(plainText); } Writer .WriteParameterSeparator() .Write($"global::{typeof(HtmlAttributeValueStyle).FullName}.{attribute.ValueStyle}") .WriteEndMethodInvocation(); } } } if (preAllocatedAttributeVariableName != null) { chunk.Attributes[i] = new TagHelperAttributeTracker( attribute.Name, new PreallocatedTagHelperAttributeChunk { AttributeVariableAccessor = preAllocatedAttributeVariableName }, attribute.ValueStyle); } } } }
private void PreAllocateUnboundTagHelperAttributes(TagHelperChunk chunk) { var boundAttributes = new HashSet <string>(StringComparer.OrdinalIgnoreCase); for (var i = 0; i < chunk.Attributes.Count; i++) { var attribute = chunk.Attributes[i]; var hasAssociatedDescriptors = chunk.Descriptors.Any(descriptor => descriptor.Attributes.Any(attributeDescriptor => attributeDescriptor.IsNameMatch(attribute.Key))); // If there's no descriptors associated or we're hitting a bound attribute a second time. if (!hasAssociatedDescriptors || !boundAttributes.Add(attribute.Key)) { string preAllocatedAttributeVariableName = null; if (attribute.Value == null) { var preAllocatedAttributeKey = new TagHelperAttributeKey(attribute.Key, value: null); if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName)) { Writer .Write("private static readonly global::") .Write(_tagHelperContext.TagHelperAttributeTypeName) .Write(" ") .Write(preAllocatedAttributeVariableName) .Write(" = ") .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName) .WriteStringLiteral(attribute.Key) .WriteEndMethodInvocation(); } } else { string plainText; if (CSharpTagHelperCodeRenderer.TryGetPlainTextValue(attribute.Value, out plainText)) { var preAllocatedAttributeKey = new TagHelperAttributeKey(attribute.Key, plainText); if (TryCachePreallocatedVariableName(preAllocatedAttributeKey, out preAllocatedAttributeVariableName)) { Writer .Write("private static readonly global::") .Write(_tagHelperContext.TagHelperAttributeTypeName) .Write(" ") .Write(preAllocatedAttributeVariableName) .Write(" = ") .WriteStartNewObject("global::" + _tagHelperContext.TagHelperAttributeTypeName) .WriteStringLiteral(attribute.Key) .WriteParameterSeparator() .WriteStartNewObject("global::" + _tagHelperContext.EncodedHtmlStringTypeName) .WriteStringLiteral(plainText) .WriteEndMethodInvocation(endLine: false) .WriteEndMethodInvocation(); } } } if (preAllocatedAttributeVariableName != null) { chunk.Attributes[i] = new KeyValuePair <string, Chunk>( attribute.Key, new PreallocatedTagHelperAttributeChunk { AttributeVariableAccessor = preAllocatedAttributeVariableName }); } } } }