// 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; using System.Globalization; using System.Linq; namespace Microsoft.Extensions.Globalization { /// /// Provides read-only cached instances of . /// public static class CultureInfoCache { private static readonly ConcurrentDictionary _cache = new ConcurrentDictionary(); /// /// Gets a read-only cached for the specified name. Only names that exist in /// will be used. /// /// The culture name. /// The cultures supported by the application. /// /// A read-only cached or null a match wasn't found in /// . /// public static CultureInfo GetCultureInfo(string name, IList supportedCultures) { // Allow only known culture names as this API is called with input from users (HTTP requests) and // creating CultureInfo objects is expensive and we don't want it to throw either. if (name == null || supportedCultures == null || !supportedCultures.Any(supportedCulture => string.Equals(supportedCulture.Name, name, StringComparison.OrdinalIgnoreCase))) { return null; } var entry = _cache.GetOrAdd(name, n => { try { return new CacheEntry(CultureInfo.ReadOnly(new CultureInfo(n))); } catch (CultureNotFoundException) { // This can still throw as the list of culture names we have is generated from latest .NET Framework // on latest Windows and thus contains names that won't be supported on lower framework or OS versions. // We can just cache the null result in these cases as it's ultimately bound by the list anyway. return new CacheEntry(cultureInfo: null); } }); return entry.CultureInfo; } private class CacheEntry { public CacheEntry(CultureInfo cultureInfo) { CultureInfo = cultureInfo; } public CultureInfo CultureInfo { get; } } } }