From 90ca64c3dde4135d6a78fa191722e928660fb0c1 Mon Sep 17 00:00:00 2001 From: damianedwards Date: Thu, 28 May 2015 12:14:03 -0700 Subject: [PATCH] Statics be gone! - Cleaned up ctors of ResourceManagerStringLocalizer and ResourceManagerWithCultureStringLocalizer too --- .../IResourceNamesCache.cs | 22 ++++++++++++++ .../ResourceManagerStringLocalizer.cs | 29 +++++++++++-------- .../ResourceManagerStringLocalizerFactory.cs | 16 ++++++---- ...sourceManagerWithCultureStringLocalizer.cs | 20 +++---------- .../ResourceNamesCache.cs | 23 +++++++++++++++ .../ResourceManagerStringLocalizerTest.cs | 12 ++++---- 6 files changed, 83 insertions(+), 39 deletions(-) create mode 100644 src/Microsoft.Framework.Localization/IResourceNamesCache.cs create mode 100644 src/Microsoft.Framework.Localization/ResourceNamesCache.cs diff --git a/src/Microsoft.Framework.Localization/IResourceNamesCache.cs b/src/Microsoft.Framework.Localization/IResourceNamesCache.cs new file mode 100644 index 0000000000..60b7c825cc --- /dev/null +++ b/src/Microsoft.Framework.Localization/IResourceNamesCache.cs @@ -0,0 +1,22 @@ +// Copyright (c) .NET Foundation. 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.Generic; + +namespace Microsoft.Framework.Localization +{ + /// + /// Represents a cache of string names in resources. + /// + public interface IResourceNamesCache + { + /// + /// Adds a set of resource names to the cache by using the specified function, if the name does not already exist. + /// + /// The resource name to add string names for. + /// The function used to generate the string names for the resource. + /// The string names for the resource. + IList GetOrAdd(string name, Func> valueFactory); + } +} diff --git a/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizer.cs b/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizer.cs index e8b684599c..ee62f3db03 100644 --- a/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizer.cs +++ b/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizer.cs @@ -18,12 +18,10 @@ namespace Microsoft.Framework.Localization /// public class ResourceManagerStringLocalizer : IStringLocalizer { - private static readonly ConcurrentDictionary> _resourceNamesCache = - new ConcurrentDictionary>(); - private readonly ConcurrentDictionary _missingManifestCache = new ConcurrentDictionary(); + private readonly IResourceNamesCache _resourceNamesCache; private readonly ResourceManager _resourceManager; private readonly AssemblyWrapper _resourceAssemblyWrapper; private readonly string _resourceBaseName; @@ -34,11 +32,13 @@ namespace Microsoft.Framework.Localization /// The to read strings from. /// The that contains the strings as embedded resources. /// The base name of the embedded resource in the that contains the strings. + /// Cache of the list of strings for a given resource assembly name. public ResourceManagerStringLocalizer( [NotNull] ResourceManager resourceManager, [NotNull] Assembly resourceAssembly, - [NotNull] string baseName) - : this(resourceManager, new AssemblyWrapper(resourceAssembly), baseName) + [NotNull] string baseName, + [NotNull] IResourceNamesCache resourceNamesCache) + : this(resourceManager, new AssemblyWrapper(resourceAssembly), baseName, resourceNamesCache) { } @@ -49,11 +49,13 @@ namespace Microsoft.Framework.Localization public ResourceManagerStringLocalizer( [NotNull] ResourceManager resourceManager, [NotNull] AssemblyWrapper resourceAssemblyWrapper, - [NotNull] string baseName) + [NotNull] string baseName, + [NotNull] IResourceNamesCache resourceNamesCache) { _resourceAssemblyWrapper = resourceAssemblyWrapper; _resourceManager = resourceManager; _resourceBaseName = baseName; + _resourceNamesCache = resourceNamesCache; } /// @@ -85,10 +87,16 @@ namespace Microsoft.Framework.Localization public IStringLocalizer WithCulture(CultureInfo culture) { return culture == null - ? new ResourceManagerStringLocalizer(_resourceManager, _resourceAssemblyWrapper, _resourceBaseName) - : new ResourceManagerWithCultureStringLocalizer(_resourceManager, - _resourceAssemblyWrapper, + ? new ResourceManagerStringLocalizer( + _resourceManager, + _resourceAssemblyWrapper.Assembly, _resourceBaseName, + _resourceNamesCache) + : new ResourceManagerWithCultureStringLocalizer( + _resourceManager, + _resourceAssemblyWrapper.Assembly, + _resourceBaseName, + _resourceNamesCache, culture); } @@ -143,9 +151,6 @@ namespace Microsoft.Framework.Localization } } - // Internal to allow testing - internal static void ClearResourceNamesCache() => _resourceNamesCache.Clear(); - private IEnumerable GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture) { var currentCulture = startingCulture; diff --git a/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizerFactory.cs b/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizerFactory.cs index 92899e15a4..d0ebe781a1 100644 --- a/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizerFactory.cs +++ b/src/Microsoft.Framework.Localization/ResourceManagerStringLocalizerFactory.cs @@ -5,7 +5,6 @@ using System; using System.Reflection; using System.Resources; using Microsoft.Framework.Internal; -using Microsoft.Framework.Localization.Internal; using Microsoft.Framework.Runtime; namespace Microsoft.Framework.Localization @@ -15,6 +14,8 @@ namespace Microsoft.Framework.Localization /// public class ResourceManagerStringLocalizerFactory : IStringLocalizerFactory { + private readonly IResourceNamesCache _resourceNamesCache = new ResourceNamesCache(); + private readonly IApplicationEnvironment _applicationEnvironment; /// @@ -35,9 +36,13 @@ namespace Microsoft.Framework.Localization public IStringLocalizer Create([NotNull] Type resourceSource) { var typeInfo = resourceSource.GetTypeInfo(); - var assembly = new AssemblyWrapper(typeInfo.Assembly); + var assembly = typeInfo.Assembly; var baseName = typeInfo.FullName; - return new ResourceManagerStringLocalizer(new ResourceManager(resourceSource), assembly, baseName); + return new ResourceManagerStringLocalizer( + new ResourceManager(resourceSource), + assembly, + baseName, + _resourceNamesCache); } /// @@ -52,8 +57,9 @@ namespace Microsoft.Framework.Localization return new ResourceManagerStringLocalizer( new ResourceManager(baseName, assembly), - new AssemblyWrapper(assembly), - baseName); + assembly, + baseName, + _resourceNamesCache); } } } \ No newline at end of file diff --git a/src/Microsoft.Framework.Localization/ResourceManagerWithCultureStringLocalizer.cs b/src/Microsoft.Framework.Localization/ResourceManagerWithCultureStringLocalizer.cs index a451b10dbc..bc79cf838b 100644 --- a/src/Microsoft.Framework.Localization/ResourceManagerWithCultureStringLocalizer.cs +++ b/src/Microsoft.Framework.Localization/ResourceManagerWithCultureStringLocalizer.cs @@ -6,7 +6,6 @@ using System.Globalization; using System.Reflection; using System.Resources; using Microsoft.Framework.Internal; -using Microsoft.Framework.Localization.Internal; namespace Microsoft.Framework.Localization { @@ -24,26 +23,15 @@ namespace Microsoft.Framework.Localization /// The to read strings from. /// The that contains the strings as embedded resources. /// The base name of the embedded resource in the that contains the strings. + /// Cache of the list of strings for a given resource assembly name. /// The specific to use. public ResourceManagerWithCultureStringLocalizer( [NotNull] ResourceManager resourceManager, - [NotNull] Assembly assembly, + [NotNull] Assembly resourceAssembly, [NotNull] string baseName, + [NotNull] IResourceNamesCache resourceNamesCache, [NotNull] CultureInfo culture) - : base(resourceManager, assembly, baseName) - { - _culture = culture; - } - - /// - /// Intended for testing purposes only. - /// - public ResourceManagerWithCultureStringLocalizer( - [NotNull] ResourceManager resourceManager, - [NotNull] AssemblyWrapper assemblyWrapper, - [NotNull] string baseName, - [NotNull] CultureInfo culture) - : base(resourceManager, assemblyWrapper, baseName) + : base(resourceManager, resourceAssembly, baseName, resourceNamesCache) { _culture = culture; } diff --git a/src/Microsoft.Framework.Localization/ResourceNamesCache.cs b/src/Microsoft.Framework.Localization/ResourceNamesCache.cs new file mode 100644 index 0000000000..27ba70cf95 --- /dev/null +++ b/src/Microsoft.Framework.Localization/ResourceNamesCache.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. 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.Generic; + +namespace Microsoft.Framework.Localization +{ + /// + /// An implementation of backed by a . + /// + public class ResourceNamesCache : IResourceNamesCache + { + private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>(); + + /// + public IList GetOrAdd(string name, Func> valueFactory) + { + return _cache.GetOrAdd(name, valueFactory); + } + } +} diff --git a/test/Microsoft.Framework.Localization.Test/ResourceManagerStringLocalizerTest.cs b/test/Microsoft.Framework.Localization.Test/ResourceManagerStringLocalizerTest.cs index 410fc2c50f..92191c0bf8 100644 --- a/test/Microsoft.Framework.Localization.Test/ResourceManagerStringLocalizerTest.cs +++ b/test/Microsoft.Framework.Localization.Test/ResourceManagerStringLocalizerTest.cs @@ -17,12 +17,12 @@ namespace Microsoft.Framework.Localization.Test public void EnumeratorCachesCultureWalkForSameAssembly() { // Arrange - ResourceManagerStringLocalizer.ClearResourceNamesCache(); + var resourceNamesCache = new ResourceNamesCache(); var baseName = "test"; var resourceAssembly = new TestAssemblyWrapper(); var resourceManager = new TestResourceManager(baseName, resourceAssembly.Assembly); - var localizer1 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName); - var localizer2 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName); + var localizer1 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName, resourceNamesCache); + var localizer2 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName, resourceNamesCache); // Act for (int i = 0; i < 5; i++) @@ -40,14 +40,14 @@ namespace Microsoft.Framework.Localization.Test public void EnumeratorCacheIsScopedByAssembly() { // Arrange - ResourceManagerStringLocalizer.ClearResourceNamesCache(); + var resourceNamesCache = new ResourceNamesCache(); var baseName = "test"; var resourceAssembly1 = new TestAssemblyWrapper("Assembly1"); var resourceAssembly2 = new TestAssemblyWrapper("Assembly2"); var resourceManager1 = new TestResourceManager(baseName, resourceAssembly1.Assembly); var resourceManager2 = new TestResourceManager(baseName, resourceAssembly2.Assembly); - var localizer1 = new ResourceManagerStringLocalizer(resourceManager1, resourceAssembly1, baseName); - var localizer2 = new ResourceManagerStringLocalizer(resourceManager2, resourceAssembly2, baseName); + var localizer1 = new ResourceManagerStringLocalizer(resourceManager1, resourceAssembly1, baseName, resourceNamesCache); + var localizer2 = new ResourceManagerStringLocalizer(resourceManager2, resourceAssembly2, baseName, resourceNamesCache); // Act localizer1.ToList();