Как проверить существование культуры в .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 -- почему? Это очень хорошее использование 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
@ Джон, согласен, что без контекста это не так убедительно. Тем не менее, мы почти всегда упускаем из виду большую часть контекста наших вопросов, поскольку мы не можем связать 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+. source = ссылка - 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 немного более эффективен, когда ввод действителен, но значительно менее эффективен в противном случае: 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