diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Snapshot/Dependency.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Snapshot/Dependency.cs index f7681a6b25e..377581b7957 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Snapshot/Dependency.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed.VS/ProjectSystem/VS/Tree/Dependencies/Snapshot/Dependency.cs @@ -1,17 +1,22 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Concurrent; using System.Collections.Immutable; using System.Globalization; using System.Linq; +using System.Text; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.CrossTarget; using Microsoft.VisualStudio.ProjectSystem.VS.Utilities; +using Microsoft.VisualStudio.Text; namespace Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.Snapshot { internal class Dependency : IDependency { + private static ConcurrentBag s_builderPool = new ConcurrentBag(); + // These priorities are for graph nodes only and are used to group graph nodes // appropriatelly in order groups predefined order instead of alphabetically. // Order is not changed for top dependency nodes only for grpah hierarchies. @@ -331,7 +336,31 @@ public static string GetID(ITargetFramework targetFramework, string providerType Requires.NotNullOrEmpty(providerType, nameof(providerType)); Requires.NotNullOrEmpty(modelId, nameof(modelId)); - return $"{targetFramework.ShortName}\\{providerType}\\{Normalize(modelId)}".TrimEnd(CommonConstants.BackSlashDelimiter); + StringBuilder sb = null; + try + { + int length = targetFramework.ShortName.Length + providerType.Length + 2; + if (!s_builderPool.TryTake(out sb)) + { + sb = new StringBuilder(length); + } + + sb.Append(targetFramework.ShortName).Append('\\'); + sb.Append(providerType).Append('\\'); + sb.Append(Normalize(modelId)); + sb.TrimEnd(CommonConstants.BackSlashDelimiter); + return sb.ToString(); + } + finally + { + sb.Clear(); + + // Prevent holding on to large builders + if (sb.Length < 1000) + { + s_builderPool.Add(sb); + } + } } private static string GetFullPath(string originalItemSpec, string containingProjectPath) diff --git a/src/Microsoft.VisualStudio.ProjectSystem.Managed/Text/StringBuilderExtensions.cs b/src/Microsoft.VisualStudio.ProjectSystem.Managed/Text/StringBuilderExtensions.cs index 7029fa0f7d2..8af6edbba75 100644 --- a/src/Microsoft.VisualStudio.ProjectSystem.Managed/Text/StringBuilderExtensions.cs +++ b/src/Microsoft.VisualStudio.ProjectSystem.Managed/Text/StringBuilderExtensions.cs @@ -46,5 +46,29 @@ public static void AppendFormat(this StringBuilder builder, StringFormat format) builder.AppendFormat(format.Format, format.Arguments); } } + + public static StringBuilder TrimEnd(this StringBuilder builder, params char[] trimChars) + { + while (builder.Length > 0) + { + var match = false; + foreach (var c in trimChars) + { + if (builder[builder.Length - 1] == c) + { + match = true; + builder.Length--; + break; + } + } + + if (!match) + { + return builder; + } + } + + return builder; + } } }