Как да проверите съществуването на култура в .NET

Имам този код, когато се опитам да получа несъществуваща култура, получавам изключение.
Съществува ли метод като TryGetCultureInfo, който връща bool стойност? Не искам да използвам израз try-catch

CultureInfo culture = CultureInfo.GetCultureInfo(cultureCode);
if (culture == null)
{
    culture = CultureInfo.GetCultureInfo(DefaultCultureCode);
}

person Jacek    schedule 05.12.2012    source източник
comment
Не искам да използвам оператор try-catch -- защо? Това е идеално добро използване на опита/хващане.   -  person Jon    schedule 05.12.2012
comment
Когато очаквате да получите конкретна култура и тя не съществува, това е изключение.   -  person Shiplu Mokaddim    schedule 05.12.2012
comment
@Jon и shiplu.mokadd.im - Има много основателни причини да избягвате опитване/хващане. Търсих отговор на този въпрос, защото моето приложение изброява поддиректория на моята папка bin и се опитва да определи дали името на тази директория е валидно име на култура, което показва, че съдържа сателитни ресурси, така че приложението може да включва валидни култури в падащо меню. Това не е случай на очакване ценността да бъде култура. Сега моята програма за отстраняване на грешки продължава да се поврежда при това ненужно изключение.   -  person DannyMeister    schedule 30.05.2014
comment
@DannyMeister: Звучи сякаш трябва да деактивирате изключенията при първа възможност в програмата за отстраняване на грешки. Във вашия случай също бих избегнал try/catch, но това е поради допълнителния контекст, който сте предоставили. Без контекст няма убедителна причина да го избягвате.   -  person Jon    schedule 30.05.2014
comment
@Jon, съгласен съм, че без контекст не е толкова завладяващо. Въпреки това почти винаги пропускаме голяма част от контекста на нашите въпроси, тъй като не можем да свържем 10-годишната история на нашите приложения, корпоративната политика, която ни ограничава и т.н., но може би въпросите трябва да бъдат по-ясни. Що се отнася до прекъсването при изключения при първа възможност... това е най-полезният инструмент за отстраняване на грешки, който някога съм срещал! 90% от бъговете, които срещам, могат да бъдат намерени веднага чрез прекъсване на изключения. Ако не го направите, тогава собствената обработка на изключенията на вашето приложение ще замъгли проблема.   -  person DannyMeister    schedule 30.05.2014
comment
@DannyMeister: Ако вашето собствено обработване на изключения скрива проблема, значи правите нещо нередно. Изключенията се хвърлят и улавят вътрешно в BCL през цялото време.   -  person Jon    schedule 30.05.2014
comment
@Jon, единият метод оставя вашия дебъгер на мястото на проблем (или близо до него), докато другият проследява грешка и продължава, но не оставя вашия дебъгер на мястото на проблема. Кое е по-лесно за отстраняване на грешки? Що се отнася до склонността на .NET библиотеката към често хвърляне и прихващане на изключения, жалко. Въпреки това, когато дебъгваме само нашия собствен код, те обикновено не се намесват. Основното нещо, което искам от разработчиците да направят, е да спрат да третират очакваните ситуации като изключителни ситуации. Това се свежда до присъда. Греша от страна на производителността и лекотата на отстраняване на грешки.   -  person DannyMeister    schedule 31.05.2014
comment
@Jon, изискванията на автора за изключения имат смисъл. Има режийни разходи, свързани с хвърлянето и прихващането на изключения. Ако може да се избегне, значи трябва да бъде. За най-голямо съжаление в този случай изглежда, че няма друг (ефикасен) начин да направите това, освен да хванете CultureNotFoundException.   -  person Crono    schedule 15.03.2016


Отговори (4)


Мисля, че няма такъв метод. Така че можете просто да try-catch или да проверите всички инсталирани култури:

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;
}

Но бих предпочел try-catch, сигурен съм, че е по-ефективен.

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;
}
person Tim Schmelter    schedule 05.12.2012
comment
Хванете конкретния тип изключение - person Aidan Ryan; 15.02.2013
comment
@AidanRyan: Защо? Ограждам много специфична част с Try-Catch, което предизвиква изключение само когато дадените cultureCode или DefaultCultureCode са null или не са налични. В този случай трябва да се върне към CultureInfo.CurrentCulture. Според мен параметрите на типа изключение биха били просто шум и биха направили кода по-малко четлив. Някой би предположил, че изключението се използва някъде или че изобщо има значение. - person Tim Schmelter; 15.02.2013
comment
Тъй като искате да хванете само CultureNotFoundException - типът има значение. Има много други изключения, които може да възникнат, които вероятно не искате да преглътнете тук: ArgumentNullException или OutOfMemoryException, например. Освен това никой няма да си помисли, че използвате изключението, ако не наименувате параметъра -- catch (CultureNotFoundException) { culture = CultureInfo.CurrentCulture; }. Той демонстрира вашата точна цел и какво точно очаквате да се случи. - person Aidan Ryan; 15.02.2013
comment
@AidanRyan: Някак си пропуснах CultureNotFoundException ;) Добре, разбрах, редактирах отговора. Благодаря. - person Tim Schmelter; 15.02.2013
comment
Само искам да отбележа, че в 3.5 и по-ранни версии на .NET изключението, което се хвърля, е наистина ArgumentException. Изключението CultureNotFoundException е само за 4+. източник = връзка - person Rich; 18.10.2013
comment
@AidanRyan OutOfMemoryException може да не е толкова обичайно при получаване на култура :), но може да се случи от други теми. (Предполагам обаче, че други теми получават изключение). По-подходящо би било ThreadAbortException ... - person ; 04.08.2016
comment
CultureInfo.GetCultureInfo("asd"); няма да хвърли Exception. Така че този отговор е грешен! - person Dominic Jonas; 15.03.2018
comment
Try-catch е малко по-ефективен, когато входът е валиден, но значително по-малко ефективен в противен случай: gist.github. com/concubicycle/b8aaaae4ddb6d8bd2d05bba0a1686cb1. Бих предпочел решение, което не използва try-catch за контролен поток. - person Sava B.; 15.01.2019
comment
@DominicJonas Според MSDN тази промяна в поведението е ефективна само ако работите с Windows 10 или по-нова версия. - person RobSiklos; 11.03.2019
comment
@DominicJonas (и RobSiklos) е прав! В по-новите версии на Windows, като Windows 10, CultureNotFoundException вече не се хвърля. ОС е доволна от всеки несъществуващ код. Така че това try-catch не е добра идея от днес. Вижте нишката Invalid CultureInfo вече не хвърля CultureNotFoundException. В Windows 10 .LCID от полученото съмнително CultureInfo изглежда винаги е 4096. Може би бихте могли да разчитате на това? - person Jeppe Stig Nielsen; 30.10.2019

Можете да напишете метод DoesCultureExist, връщащ булева стойност точно като тази:

private static bool DoesCultureExist(string cultureName)
{
    return CultureInfo.GetCultures(CultureTypes.AllCultures).Any(culture => string.Equals(culture.Name, cultureName, StringComparison.CurrentCultureIgnoreCase));
}
person Steven S.    schedule 10.05.2013
comment
Позволих си да редактирам кода ви, така че този регистър да се игнорира, тъй като това е начинът, по който CultureInfo обикновено работи. - person Crono; 15.03.2016

Ако искате да е бързо можете да използвате:

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;
    }
}
person Johan Larsson    schedule 11.04.2016
comment
Това трябва да е предпочитаният отговор, тъй като трябва да се избягват изключения като контрол на потока. - person Sava B.; 15.01.2019

Не, AFAIK не е възможен. Можете първо да проверите дали културата съществува и в такъв случай да я получите.

Следният код показва как да го направите:

    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;
    }

Дано помогне

person Daniel Peñalba    schedule 05.12.2012