Reputation: 12053
I have this code, when I try to get not existed culture I get exception.
Is there exists method like TryGetCultureInfo
, which return bool
value? I don't want to use try-catch
statement
CultureInfo culture = CultureInfo.GetCultureInfo(cultureCode);
if (culture == null)
{
culture = CultureInfo.GetCultureInfo(DefaultCultureCode);
}
Upvotes: 25
Views: 31371
Reputation: 10350
The accepted answer is slow. You might use another solution for a better performance: CultureInfo.GetCultureInfo
wrapped in a try-catch clause.
Even though the try-catch is generally not a good idea, I would suggest using the CultureInfo.GetCultureInfo
wrapped in the catch CultureNotFoundException
clause anyway.
Most importantly, GetCultureInfo
has a thread-safe (!) cached culture names, so there's no lookup on each call.
public static bool Exists(string name)
{
try
{
CultureInfo.GetCultureInfo(name);
return true;
}
catch (CultureNotFoundException)
{
return false;
}
}
I've made a benchmark to check which method is faster and GetCultureInfo
is significantly (over 4000x) faster.
Result:
BenchmarkDotNet v0.13.9+228a464e8be6c580ad9408e98f18813f6407fb5a, Windows 11 (10.0.22621.2506/22H2/2022Update/SunValley2)
12th Gen Intel Core i5-12400F, 1 CPU, 12 logical and 6 physical cores
.NET SDK 7.0.403
[Host] : .NET 7.0.13 (7.0.1323.51816), X64 RyuJIT AVX2
DefaultJob : .NET 7.0.13 (7.0.1323.51816), X64 RyuJIT AVX2
| Method | Mean | Error | StdDev |
|------------------------ |-------------:|-------------:|-------------:|
| GetCultureInfo_TryCatch | 19.88 ns | 0.372 ns | 0.330 ns |
| GetCultures | 83,831.36 ns | 1,638.645 ns | 2,599.065 ns |
[SimpleJob]
public class CultureExistsBenchmarks
{
[Benchmark]
public void GetCultureInfo_TryCatch()
{
try { CultureInfo.GetCultureInfo("zzz"); }
catch (CultureNotFoundException) { }
}
[Benchmark]
public void GetCultures() =>
CultureInfo.GetCultures(CultureTypes.AllCultures).Any(culture => string.Equals(culture.Name, "zzz", StringComparison.CurrentCultureIgnoreCase));
}
As an alternative approach, which is culture-agnostic, if you don't mind the dialect of the language, you may construct list of strings with ISO 639-2 language codes and make lookup for it.
Upvotes: 3
Reputation: 744
For whom it may interest, starting with .NET 5 this overload does exaclty that (efficiently calling Nls or Icu native API).
Upvotes: 0
Reputation: 17580
If you want it to be fast you can use:
internal static class Culture
{
private static readonly HashSet<string> CultureNames = CreateCultureNames();
internal static bool Exists(string name)
{
return CultureNames.Contains(name);
}
private static HashSet<string> CreateCultureNames()
{
var cultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(x => !string.IsNullOrEmpty(x.Name))
.ToArray();
var allNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
allNames.UnionWith(cultureInfos.Select(x => x.TwoLetterISOLanguageName));
allNames.UnionWith(cultureInfos.Select(x => x.Name));
return allNames;
}
}
Upvotes: 14
Reputation: 734
You could write a DoesCultureExist method returning a boolean value just like this:
private static bool DoesCultureExist(string cultureName)
{
return CultureInfo.GetCultures(CultureTypes.AllCultures).Any(culture => string.Equals(culture.Name, cultureName, StringComparison.CurrentCultureIgnoreCase));
}
Upvotes: 38
Reputation: 460018
I think there's no such method. So you could just try-catch
or check all installed cultures:
string cultureCode = "de-DE";
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures & ~CultureTypes.NeutralCultures);
var culture = cultures.FirstOrDefault(c => c.Name.Equals(cultureCode, StringComparison.OrdinalIgnoreCase));
if (culture == null)
{
culture = cultures.FirstOrDefault(c => c.Name.Equals(DefaultCultureCode, StringComparison.OrdinalIgnoreCase));
if (culture == null)
culture = CultureInfo.CurrentCulture;
}
But i would prefer the try-catch
, i'm sure it is more efficient.
public bool TryGetCultureInfo(string cultureCode, string DefaultCultureCode, out CultureInfo culture)
{
try
{
culture = CultureInfo.GetCultureInfo(cultureCode);
return true;
} catch(CultureNotFoundException)
{
if (DefaultCultureCode == null)
culture = CultureInfo.CurrentCulture;
else
{
try
{
culture = CultureInfo.GetCultureInfo(DefaultCultureCode);
} catch (CultureNotFoundException)
{
culture = CultureInfo.CurrentCulture;
}
}
}
return false;
}
Upvotes: 23
Reputation: 31847
No, AFAIK is not possible. You can check first if the culture exists and in that case get it.
The following code shows how to do it:
private static CultureInfo GetCulture(string name)
{
if (!CultureExists(name)) return null;
return CultureInfo.GetCultureInfo(name);
}
private static bool CultureExists(string name)
{
CultureInfo[] availableCultures =
CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo culture in availableCultures)
{
if (culture.Name.Equals(name))
return true;
}
return false;
}
Hope it helps
Upvotes: 3