aspnetcore/src/Microsoft.Extensions.Global.../CultureInfoCache.cs

68 lines
2.7 KiB
C#

// 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
{
/// <summary>
/// Provides read-only cached instances of <see cref="CultureInfo"/>.
/// </summary>
public static class CultureInfoCache
{
private static readonly ConcurrentDictionary<string, CacheEntry> _cache = new ConcurrentDictionary<string, CacheEntry>();
/// <summary>
/// Gets a read-only cached <see cref="CultureInfo"/> for the specified name. Only names that exist in
/// <see cref="KnownCultureNames"/> will be used.
/// </summary>
/// <param name="name">The culture name.</param>
/// <param name="supportedCultures">The cultures supported by the application.</param>
/// <returns>
/// A read-only cached <see cref="CultureInfo"/> or <c>null</c> a match wasn't found in
/// <see cref="KnownCultureNames"/>.
/// </returns>
public static CultureInfo GetCultureInfo(string name, IList<CultureInfo> 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; }
}
}
}