Classe CultureInfo

Este artigo fornece observações complementares à documentação de referência para esta API.

A classe CultureInfo fornece informações específicas da cultura, como idioma, dialeto, país/região, calendário e convenções associadas a uma cultura específica. Essa classe também fornece acesso a instâncias específicas da cultura dos objetos DateTimeFormatInfo, NumberFormatInfo, CompareInfo e TextInfo. Esses objetos contêm as informações necessárias para operações específicas da cultura, como maiúsculas, datas e números de formatação e comparação de cadeias de caracteres. A classe CultureInfo é usada direta ou indiretamente por classes que formatam, analisam ou manipulam dados específicos da cultura, como String, DateTime, DateTimeOffset e os tipos numéricos.

Nomes e identificadores de cultura

A classe CultureInfo especifica um nome exclusivo para cada cultura, com base no RFC 4646. O nome é uma combinação de um código de cultura de duas letras ISO 639 ou de três letras minúsculas associado a uma linguagem e um código de subcultura maiúscula de duas letras ISO 3166 associado a um país ou região. Além disso, para aplicativos em execução no Windows 10 ou posterior, há suporte para nomes de cultura que correspondem a marcas de idioma BCP-47 válidas.

Observação

Quando um nome de cultura é passado para um construtor de classe ou um método como CreateSpecificCulture ou CultureInfo, maiúsculas e minúsculas não são significativas.

O formato do nome da cultura com base no RFC 4646 é languagecode2-country/regioncode2, em que languagecode2 é o código de idioma de duas letras e country/regioncode2 é o código de subcultura de duas letras. Exemplos incluem ja-JP para japonês (Japão) e en-US para inglês (Estados Unidos). Nos casos em que um código de idioma de duas letras não está disponível, um código de três letras, conforme definido no ISO 639-3, é usado.

Alguns nomes de cultura também especificam um script ISO 15924. Por exemplo, Cyrl especifica o script cirílico e Latn especifica o script latino. Um nome de cultura que inclui um script usa o padrão languagecode2country/regioncode2-scripttag-. Um exemplo desse tipo de nome de cultura é uz-Cyrl-UZ para uzbeque (cirílico, Uzbequistão). Em sistemas operacionais Windows antes do Windows Vista, um nome de cultura que inclui um script usa o padrão languagecode2--country/regioncode2scripttag, por exemplo, uz-UZ-Cyrl para uzbeque (Cirílico, Uzbequistão).

Uma cultura neutra é especificada apenas pelo código de linguagem minúscula de duas letras. Por exemplo, fr especifica a cultura neutra para francês e de especifica a cultura neutra para o alemão.

Observação

Há dois nomes de cultura que contradizem essa regra. As culturas chinesa (simplificada), nomeada zh-Hans, e chinesa (tradicional), nomeada zh-Hant, são culturas neutras. Os nomes de cultura representam o padrão atual e devem ser usados, a menos que você tenha um motivo para usar os nomes mais antigos zh-CHS e zh-CHT.

Um identificador de cultura é uma abreviação numérica internacional padrão e tem os componentes necessários para identificar exclusivamente uma das culturas instaladas. Seu aplicativo pode usar identificadores de cultura predefinidos ou definir identificadores personalizados.

Determinados nomes e identificadores de cultura predefinidos são usados por essa e outras classes no namespace System.Globalization. Para obter informações detalhadas de cultura para sistemas Windows, confira a coluna Marca de idioma na lista de nomes de idioma/região com suporte do Windows. Os nomes de cultura seguem o padrão definido pelo BCP 47.

Os nomes e identificadores de cultura representam apenas um subconjunto de culturas que podem ser encontradas em um computador específico. Versões do Windows ou service packs podem alterar as culturas disponíveis. Os aplicativos podem adicionar culturas personalizadas usando a classe CultureAndRegionInfoBuilder. Os usuários podem adicionar suas próprias culturas personalizadas usando a ferramenta Microsoft Locale Builder. O Microsoft Locale Builder é escrito em código gerenciado usando a classe CultureAndRegionInfoBuilder.

Vários nomes distintos estão intimamente associados a uma cultura, notadamente os nomes associados aos seguintes membros da classe:

Culturas invariável, neutra e específica

As culturas geralmente são agrupadas em três conjuntos: culturas invariáveis, culturas neutras e culturas específicas.

Uma cultura invariável não diferencia a cultura. Seu aplicativo especifica a cultura invariável por nome usando uma cadeia de caracteres vazia ("") ou por seu identificador. InvariantCulture define uma instância da cultura invariável. Ele está associado ao idioma inglês, mas não a nenhum país/região. Ele é usado em quase qualquer método no namespace Globalization que requeira uma cultura.

Uma cultura neutra é uma cultura associada a um idioma, mas não a um país/região. Uma cultura específica é uma cultura associada a um idioma e a um país/região. Por exemplo, fr é o nome neutro da cultura francesa e fr-FR é o nome da cultura francesa específica (França). Observe que chinês (simplificado) e chinês (tradicional) também são considerados culturas neutras.

Não é recomendável criar uma instância de uma classe CompareInfo para uma cultura neutra porque os dados que ela contém são arbitrários. Para exibir e classificar dados, especifique o idioma e a região. Além disso, a propriedade Name de um objeto CompareInfo criado para uma cultura neutra retorna apenas o país e não inclui a região.

As culturas definidas têm uma hierarquia na qual o pai de uma cultura específica é uma cultura neutra e o pai de uma cultura neutra é a cultura invariável. A propriedade Parent contém a cultura neutra associada a uma cultura específica. As culturas personalizadas devem definir a propriedade Parent em conformidade com esse padrão.

Se os recursos de uma cultura específica não estiverem disponíveis no sistema operacional, os recursos para a cultura neutra associada serão usados. Se os recursos para a cultura neutra não estiverem disponíveis, os recursos inseridos no assembly principal serão usados. Para obter mais informações sobre o processo de fallback de recursos, confira Empacotamento e implantação de recursos.

A lista de localidades na API do Windows é ligeiramente diferente da lista de culturas com suporte do .NET. Se a interoperabilidade com o Windows for necessária, por exemplo, por meio do mecanismo p/invoke, o aplicativo deverá usar uma cultura específica definida para o sistema operacional. O uso da cultura específica garante a consistência com a localidade equivalente do Windows, que é identificada com um identificador de localidade igual a LCID.

Um DateTimeFormatInfo ou NumberFormatInfo pode ser criado apenas para a cultura invariável ou para culturas específicas, não para culturas neutras.

Se DateTimeFormatInfo.Calendar for TaiwanCalendar, mas Thread.CurrentCulture não estiver definido como zh-TW, então DateTimeFormatInfo.NativeCalendarName, DateTimeFormatInfo.GetEraName e DateTimeFormatInfo.GetAbbreviatedEraName retornam uma cadeia de caracteres vazia ("").

Culturas personalizadas

No Windows, você pode criar localidades personalizadas. Para obter mais informações, confira Localidades personalizadas.

CultureInfo e dados culturais

O .NET deriva seus dados culturais de uma de várias fontes, dependendo da implementação, da plataforma e da versão:

  • Em todas as versões do .NET (Core) em execução em plataformas Unix ou no Windows 10 e versões posteriores, os dados culturais são fornecidos pela Biblioteca de Componentes Internacionais para Unicode (ICU). A versão específica da Biblioteca ICU depende do sistema operacional individual.
  • Em todas as versões do .NET (Core) em execução no Windows 9 e versões anteriores, os dados culturais são fornecidos pelo sistema operacional Windows.
  • No .NET Framework 4 e versões posteriores, os dados culturais são fornecidos pelo sistema operacional Windows.

Por isso, uma cultura disponível em uma determinada implementação, plataforma ou versão do .NET pode não estar disponível em uma implementação, plataforma ou versão do .NET diferente.

Alguns objetos CultureInfo diferem dependendo da plataforma subjacente. Em particular, zh-CN, ou chinês (simplificado, China), e zh-TW, ou chinês (tradicional, Taiwan), são culturas disponíveis em sistemas Windows, mas são culturas com alias em sistemas Unix. "zh-CN" é um alias para a cultura "zh-Hans-CN", e "zh-TW" é um alias para a cultura "zh-Hant-TW". As culturas com alias não são retornadas por chamadas para o método GetCultures e podem ter valores de propriedade diferentes, incluindo culturas Parent diferentes de seus equivalentes do Windows. Para as culturas zh-CN e zh-TW, esses diferenciais incluem o seguinte:

  • Nos sistemas Windows, a cultura pai da cultura "zh-CN" é "zh-Hans", e a cultura pai da cultura "zh-TW" é "zh-Hant". A cultura pai dessas duas culturas é "zh". Nos sistemas Unix, os pais de ambas as culturas são "zh". Isso significa que, se você não fornecer recursos específicos à cultura para as culturas "zh-CN" ou "zh-TW", mas fornecer recursos para a cultura neutra "zh-Hans" ou "zh-Hant", seu aplicativo carregará os recursos para a cultura neutra no Windows, mas não no Unix. Em sistemas Unix, você deve definir explicitamente os threads CurrentUICulture como "zh-Hans" ou "zh-Hant".

  • Em sistemas Windows, chamar CultureInfo.Equals em uma instância que representa a cultura "zh-CN" e passá-la uma instância "zh-Hans-CN" retorna true. Em sistemas Unix, a chamada de método retorna false. Esse comportamento também se aplica à chamada de Equals em uma instância "zh-TW" CultureInfo e a passar uma instância "zh-Hant-Tw" a ela.

Dados de cultura dinâmicos

Exceto pela cultura invariável, os dados de cultura são dinâmicos. Isso é verdade mesmo para as culturas predefinidas. Por exemplo, países ou regiões adotam novas moedas, alteram a ortografia de palavras ou alteram seu calendário preferido e as definições de cultura mudam para refletir tais mudanças. As culturas personalizadas estão sujeitas a alterações sem aviso prévio, e qualquer cultura específica pode ser substituída por uma cultura de substituição personalizada. Além disso, conforme discutido abaixo, um usuário individual pode substituir preferências culturais. Os aplicativos sempre devem obter dados de cultura em tempo de execução.

Cuidado

Ao salvar dados, seu aplicativo deve usar a cultura invariável, um formato binário ou um formato independente de cultura específico. Os dados salvos de acordo com os valores atuais associados a uma cultura específica, além da cultura invariável, podem se tornar ilegíveis ou podem mudar de significado se essa cultura mudar.

A cultura atual e a cultura da interface do usuário atual

Cada thread em um aplicativo .NET tem uma cultura atual e uma cultura de interface do usuário atual. A cultura atual determina as convenções de formatação para datas, horas, números e valores de moeda, a ordem de classificação de texto, convenções de maiúsculas e minúsculas e as maneiras pelas quais as cadeias de caracteres são comparadas. A cultura da interface do usuário atual é usada para recuperar recursos específicos da cultura em tempo de execução.

Observação

Para obter informações sobre como a cultura atual e a cultura da interface do usuário atual é determinada por thread, confira a seção Cultura e threads. Para obter informações sobre como a cultura atual e a cultura da interface do usuário atual é determinada em threads em execução em um novo domínio de aplicativo e em threads que cruzam os limites de domínio do aplicativo, confira a seção Cultura e domínios de aplicativo. Para obter informações sobre como a cultura atual e a cultura da interface do usuário atual é determinada em threads que executam operações assíncronas baseadas em tarefas, confira a seção Cultura e operações assíncronas baseadas em tarefas.

Para obter informações mais detalhadas sobre a cultura atual, confira a propriedade CultureInfo.CurrentCulture. Para obter informações mais detalhadas sobre a cultura da interface do usuário atual, confira o tópico da propriedade CultureInfo.CurrentUICulture.

Recuperar a cultura atual e a cultura da interface do usuário atual

Você pode obter um objeto CultureInfo que representa a cultura atual de duas maneiras:

O exemplo a seguir recupera os dois valores de propriedade, faz uma comparação para mostrar que eles são iguais e exibe o nome da cultura atual.

using System;
using System.Globalization;
using System.Threading;

public class CurrentCultureEx
{
    public static void Main()
    {
        CultureInfo culture1 = CultureInfo.CurrentCulture;
        CultureInfo culture2 = Thread.CurrentThread.CurrentCulture;
        Console.WriteLine("The current culture is {0}", culture1.Name);
        Console.WriteLine("The two CultureInfo objects are equal: {0}",
                          culture1 == culture2);
    }
}
// The example displays output like the following:
//     The current culture is en-US
//     The two CultureInfo objects are equal: True

Você pode obter um objeto CultureInfo que representa a cultura da interface do usuário atual de duas maneiras:

O exemplo a seguir recupera os dois valores de propriedade, compara-os para mostrar que eles são iguais e exibe o nome da cultura da interface do usuário atual.

using System;
using System.Globalization;
using System.Threading;

public class CurrentUIEx
{
    public static void Main()
    {
        CultureInfo uiCulture1 = CultureInfo.CurrentUICulture;
        CultureInfo uiCulture2 = Thread.CurrentThread.CurrentUICulture;
        Console.WriteLine("The current UI culture is {0}", uiCulture1.Name);
        Console.WriteLine("The two CultureInfo objects are equal: {0}",
                          uiCulture1 == uiCulture2);
    }
}
// The example displays output like the following:
//     The current UI culture is en-US
//     The two CultureInfo objects are equal: True

Definir a cultura atual e a cultura da interface do usuário atual

Para alterar a cultura e a cultura da interface do usuário de um thread, faça o seguinte:

  1. Instancie um objeto CultureInfo que representa essa cultura chamando um construtor de classe CultureInfo e passando-lhe o nome da cultura. O construtor CultureInfo(String) cria uma instância de um objeto CultureInfo que reflete as substituições do usuário se a nova cultura for a mesma da cultura atual do Windows. O construtor CultureInfo(String, Boolean) permite especificar se o objeto recém-instanciado CultureInfo reflete as substituições do usuário se a nova cultura for a mesma da cultura atual do Windows.

  2. Atribua o objeto CultureInfo à propriedade CultureInfo.CurrentCulture ou CultureInfo.CurrentUICulture no .NET Core e ao .NET Framework 4.6 e versões posteriores.

O exemplo a seguir recupera a cultura atual. Se esta for diferente da cultura francesa (França), ele mudará a cultura atual para francês (França). Caso contrário, a cultura atual será alterada para francês (Luxemburgo).

using System;
using System.Globalization;

public class ChangeEx1
{
    public static void Main()
    {
        CultureInfo current = CultureInfo.CurrentCulture;
        Console.WriteLine("The current culture is {0}", current.Name);
        CultureInfo newCulture;
        if (current.Name.Equals("fr-FR"))
            newCulture = new CultureInfo("fr-LU");
        else
            newCulture = new CultureInfo("fr-FR");

        CultureInfo.CurrentCulture = newCulture;
        Console.WriteLine("The current culture is now {0}",
                          CultureInfo.CurrentCulture.Name);
    }
}
// The example displays output like the following:
//     The current culture is en-US
//     The current culture is now fr-FR

O exemplo a seguir recupera a cultura atual. Se esta for diferente da cultura eslovena (Eslovênia), ele mudará a cultura atual para eslovena (Eslovênia). Caso contrário, mudará a cultura atual para croata (Croácia).

using System;
using System.Globalization;

public class ChangeUICultureEx
{
    public static void Main()
    {
        CultureInfo current = CultureInfo.CurrentUICulture;
        Console.WriteLine("The current UI culture is {0}", current.Name);
        CultureInfo newUICulture;
        if (current.Name.Equals("sl-SI"))
            newUICulture = new CultureInfo("hr-HR");
        else
            newUICulture = new CultureInfo("sl-SI");

        CultureInfo.CurrentUICulture = newUICulture;
        Console.WriteLine("The current UI culture is now {0}",
                          CultureInfo.CurrentUICulture.Name);
    }
}
// The example displays output like the following:
//     The current UI culture is en-US
//     The current UI culture is now sl-SI

Obter todas as culturas

Você pode recuperar uma matriz de categorias específicas de culturas ou de todas as culturas disponíveis no computador local chamando o método GetCultures. Por exemplo, você pode recuperar culturas personalizadas, culturas específicas ou culturas neutras isoladamente ou em combinação.

O exemplo a seguir chama o método GetCultures duas vezes, primeiro com o membro de enumeração System.Globalization.CultureTypes para recuperar todas as culturas personalizadas e, em seguida, com o membro de enumeração System.Globalization.CultureTypes para recuperar todas as culturas de substituição.

using System;
using System.Globalization;

public class GetCulturesEx
{
    public static void Main()
    {
        // Get all custom cultures.
        CultureInfo[] custom = CultureInfo.GetCultures(CultureTypes.UserCustomCulture);
        if (custom.Length == 0)
        {
            Console.WriteLine("There are no user-defined custom cultures.");
        }
        else
        {
            Console.WriteLine("Custom cultures:");
            foreach (var culture in custom)
                Console.WriteLine("   {0} -- {1}", culture.Name, culture.DisplayName);
        }
        Console.WriteLine();

        // Get all replacement cultures.
        CultureInfo[] replacements = CultureInfo.GetCultures(CultureTypes.ReplacementCultures);
        if (replacements.Length == 0)
        {
            Console.WriteLine("There are no replacement cultures.");
        }
        else
        {
            Console.WriteLine("Replacement cultures:");
            foreach (var culture in replacements)
                Console.WriteLine("   {0} -- {1}", culture.Name, culture.DisplayName);
        }
        Console.WriteLine();
    }
}
// The example displays output like the following:
//     Custom cultures:
//        x-en-US-sample -- English (United States)
//        fj-FJ -- Boumaa Fijian (Viti)
//
//     There are no replacement cultures.

Cultura e threads

Quando um novo thread de aplicativo é iniciado, sua cultura atual e a cultura da interface do usuário atual são definidas pela cultura atual do sistema e não pela cultura de thread atual. O exemplo a seguir ilustra a diferença. Ele define a cultura atual e a cultura da interface do usuário atual de um thread de aplicativo como a cultura francesa (França) (fr-FR). Se a cultura atual já for fr-FR, o exemplo a definirá como a cultura inglesa (Estados Unidos) (en-US). Ele exibe três números aleatórios como valores de moeda e cria um novo thread, que, por sua vez, exibe mais três números aleatórios como valores de moeda. Mas, como mostra a saída do exemplo, os valores de moeda exibidos pelo novo thread não refletem as convenções de formatação da cultura francesa (França), ao contrário da saída do thread principal do aplicativo.

using System;
using System.Globalization;
using System.Threading;

public class DefaultThreadEx
{
    static Random rnd = new Random();

    public static void Main()
    {
        if (Thread.CurrentThread.CurrentCulture.Name != "fr-FR")
        {
            // If current culture is not fr-FR, set culture to fr-FR.
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR");
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("fr-FR");
        }
        else
        {
            // Set culture to en-US.
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture("en-US");
        }
        ThreadProc();

        Thread worker = new Thread(ThreadProc);
        worker.Name = "WorkerThread";
        worker.Start();
    }

    private static void DisplayThreadInfo()
    {
        Console.WriteLine("\nCurrent Thread Name: '{0}'",
                          Thread.CurrentThread.Name);
        Console.WriteLine("Current Thread Culture/UI Culture: {0}/{1}",
                          Thread.CurrentThread.CurrentCulture.Name,
                          Thread.CurrentThread.CurrentUICulture.Name);
    }

    private static void DisplayValues()
    {
        // Create new thread and display three random numbers.
        Console.WriteLine("Some currency values:");
        for (int ctr = 0; ctr <= 3; ctr++)
            Console.WriteLine("   {0:C2}", rnd.NextDouble() * 10);
    }

    private static void ThreadProc()
    {
        DisplayThreadInfo();
        DisplayValues();
    }
}
// The example displays output similar to the following:
//       Current Thread Name: ''
//       Current Thread Culture/UI Culture: fr-FR/fr-FR
//       Some currency values:
//          8,11 €
//          1,48 €
//          8,99 €
//          9,04 €
//
//       Current Thread Name: 'WorkerThread'
//       Current Thread Culture/UI Culture: en-US/en-US
//       Some currency values:
//          $6.72
//          $6.35
//          $2.90
//          $7.72

Você pode definir a cultura e a cultura da interface do usuário de todos os threads em um domínio de aplicativo atribuindo um objeto CultureInfo que representa essa cultura às propriedades DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture. O exemplo a seguir usa essas propriedades para garantir que todos os threads no domínio de aplicativo padrão compartilhem a mesma cultura.

using System;
using System.Globalization;
using System.Threading;

public class SetThreadsEx
{
    static Random rnd = new Random();

    public static void Main()
    {
        if (Thread.CurrentThread.CurrentCulture.Name != "fr-FR")
        {
            // If current culture is not fr-FR, set culture to fr-FR.
            CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR");
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("fr-FR");
        }
        else
        {
            // Set culture to en-US.
            CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("en-US");
        }
        ThreadProc();

        Thread worker = new Thread(SetThreadsEx.ThreadProc);
        worker.Name = "WorkerThread";
        worker.Start();
    }

    private static void DisplayThreadInfo()
    {
        Console.WriteLine("\nCurrent Thread Name: '{0}'",
                          Thread.CurrentThread.Name);
        Console.WriteLine("Current Thread Culture/UI Culture: {0}/{1}",
                          Thread.CurrentThread.CurrentCulture.Name,
                          Thread.CurrentThread.CurrentUICulture.Name);
    }

    private static void DisplayValues()
    {
        // Create new thread and display three random numbers.
        Console.WriteLine("Some currency values:");
        for (int ctr = 0; ctr <= 3; ctr++)
            Console.WriteLine("   {0:C2}", rnd.NextDouble() * 10);
    }

    private static void ThreadProc()
    {
        DisplayThreadInfo();
        DisplayValues();
    }
}
// The example displays output similar to the following:
//       Current Thread Name: ''
//       Current Thread Culture/UI Culture: fr-FR/fr-FR
//       Some currency values:
//          6,83 €
//          3,47 €
//          6,07 €
//          1,70 €
//
//       Current Thread Name: 'WorkerThread'
//       Current Thread Culture/UI Culture: fr-FR/fr-FR
//       Some currency values:
//          9,54 €
//          9,50 €
//          0,58 €
//          6,91 €

Aviso

Embora as propriedades DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture sejam membros estáticos, elas definem a cultura padrão e a cultura da interface do usuário padrão apenas para o domínio do aplicativo que é atual no momento em que esses valores de propriedade são definidos. Para obter mais informações, confira a próxima seção, Cultura e domínios de aplicativo.

Quando você atribui valores às propriedades DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture, a cultura e a cultura da interface do usuário dos threads no domínio do aplicativo também são alteradas se elas não tiverem sido atribuídas explicitamente a uma cultura. No entanto, esses threads refletem as novas configurações de cultura somente enquanto são executados no domínio do aplicativo atual. Se esses threads forem executados em outro domínio de aplicativo, sua cultura se tornará a cultura padrão definida para esse domínio de aplicativo. Como resultado, recomendamos que você sempre defina a cultura do thread principal do aplicativo e não confie nas propriedades DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture para alterá-la.

Domínios de cultura e aplicativo

DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture são propriedades estáticas que definem explicitamente uma cultura padrão somente para o domínio do aplicativo que é atual quando o valor da propriedade é definido ou recuperado. O exemplo a seguir define a cultura padrão e a cultura da interface do usuário padrão no domínio de aplicativo padrão como francês (França) e, em seguida, usa a classe AppDomainSetup e o delegado AppDomainInitializer para definir a cultura padrão e a cultura da interface do usuário em um novo domínio de aplicativo como russo (Rússia). Um único thread executa dois métodos em cada domínio do aplicativo. Observe que a cultura e a cultura da interface do usuário do thread não estão definidas explicitamente; elas são derivadas da cultura padrão e da cultura da interface do usuário do domínio do aplicativo no qual o thread está sendo executado. Observe também que as propriedades DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture retornam os valores padrão CultureInfo do domínio do aplicativo que é atual quando a chamada do método é feita.

using System;
using System.Globalization;

public class Example
{
    public static void Main()
    {
        // Set the default culture and display the current date in the current application domain.
        Info info1 = new Info();
        SetAppDomainCultures("fr-FR");

        // Create a second application domain.
        AppDomainSetup setup = new AppDomainSetup();
        setup.AppDomainInitializer = SetAppDomainCultures;
        setup.AppDomainInitializerArguments = new string[] { "ru-RU" };
        AppDomain domain = AppDomain.CreateDomain("Domain2", null, setup);
        // Create an Info object in the new application domain.
        Info info2 = (Info)domain.CreateInstanceAndUnwrap(typeof(Example).Assembly.FullName,
                                                           "Info");

        // Execute methods in the two application domains.
        info2.DisplayDate();
        info2.DisplayCultures();

        info1.DisplayDate();
        info1.DisplayCultures();
    }

    public static void SetAppDomainCultures(string[] names)
    {
        SetAppDomainCultures(names[0]);
    }

    public static void SetAppDomainCultures(string name)
    {
        try
        {
            CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture(name);
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture(name);
        }
        // If an exception occurs, we'll just fall back to the system default.
        catch (CultureNotFoundException)
        {
            return;
        }
        catch (ArgumentException)
        {
            return;
        }
    }
}

public class Info : MarshalByRefObject
{
    public void DisplayDate()
    {
        Console.WriteLine("Today is {0:D}", DateTime.Now);
    }

    public void DisplayCultures()
    {
        Console.WriteLine("Application domain is {0}", AppDomain.CurrentDomain.Id);
        Console.WriteLine("Default Culture: {0}", CultureInfo.DefaultThreadCurrentCulture);
        Console.WriteLine("Default UI Culture: {0}", CultureInfo.DefaultThreadCurrentUICulture);
    }
}
// The example displays the following output:
//       Today is 14 октября 2011 г.
//       Application domain is 2
//       Default Culture: ru-RU
//       Default UI Culture: ru-RU
//       Today is vendredi 14 octobre 2011
//       Application domain is 1
//       Default Culture: fr-FR
//       Default UI Culture: fr-FR

Para obter mais informações sobre culturas e domínios de aplicativo, confira a seção "Domínios e domínio do aplicativo e threads" no tópico Domínios do aplicativo.

Cultura e operações assíncronas baseadas em tarefas

O padrão de programação assíncrona baseado em tarefa usa objetos Task e Task<TResult> para executar delegados de forma assíncrona em threads do pool de threads. O thread específico no qual uma determinada tarefa é executada não é conhecido com antecedência, mas é determinado apenas em runtime.

Para aplicativos direcionados ao .NET Framework 4.6 ou a uma versão posterior, a cultura faz parte do contexto de uma operação assíncrona. Em outras palavras, as operações assíncronas, por padrão, herdam os valores das propriedades CurrentCulture e CurrentUICulture do thread do qual são iniciadas. Se a cultura atual ou a cultura da interface do usuário atual difere da cultura do sistema, a cultura atual ultrapassa os limites de thread e se torna a cultura atual do thread do pool de threads que está executando uma operação assíncrona.

O exemplo a seguir fornece uma ilustração simples. O exemplo define um delegado Func<TResult>, formatDelegate, que retorna alguns números formatados como valores de moeda. O exemplo altera a cultura atual do sistema para francês (França) ou, se francês (França) já for a cultura atual, inglês (Estados Unidos). Ele então:

  • Invoca o delegado diretamente para que ele seja executado de forma síncrona no thread principal do aplicativo.
  • Cria uma tarefa que executa o delegado de forma assíncrona em um thread do pool de threads.
  • Cria uma tarefa que executa o delegado de forma síncrona no thread do aplicativo principal chamando o método Task.RunSynchronously.

Como mostra a saída do exemplo, quando a cultura atual é alterada para francês (França), a cultura atual do thread do qual as tarefas são invocadas de forma assíncrona torna-se a cultura atual para essa operação assíncrona.

using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;

public class AsyncCultureEx1
{
    public static void Main()
    {
        decimal[] values = { 163025412.32m, 18905365.59m };
        string formatString = "C2";

        string FormatDelegate()
        {
            string output = $"Formatting using the {CultureInfo.CurrentCulture.Name} " +
            "culture on thread {Thread.CurrentThread.ManagedThreadId}.\n";
            foreach (decimal value in values)
                output += $"{value.ToString(formatString)}   ";

            output += Environment.NewLine;
            return output;
        }

        Console.WriteLine($"The example is running on thread {Thread.CurrentThread.ManagedThreadId}");
        // Make the current culture different from the system culture.
        Console.WriteLine($"The current culture is {CultureInfo.CurrentCulture.Name}");
        if (CultureInfo.CurrentCulture.Name == "fr-FR")
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
        else
            Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");

        Console.WriteLine($"Changed the current culture to {CultureInfo.CurrentCulture.Name}.\n");

        // Execute the delegate synchronously.
        Console.WriteLine("Executing the delegate synchronously:");
        Console.WriteLine(FormatDelegate());

        // Call an async delegate to format the values using one format string.
        Console.WriteLine("Executing a task asynchronously:");
        var t1 = Task.Run(FormatDelegate);
        Console.WriteLine(t1.Result);

        Console.WriteLine("Executing a task synchronously:");
        var t2 = new Task<string>(FormatDelegate);
        t2.RunSynchronously();
        Console.WriteLine(t2.Result);
    }
}
// The example displays the following output:
//         The example is running on thread 1
//         The current culture is en-US
//         Changed the current culture to fr-FR.
//
//         Executing the delegate synchronously:
//         Formatting using the fr-FR culture on thread 1.
//         163 025 412,32 €   18 905 365,59 €
//
//         Executing a task asynchronously:
//         Formatting using the fr-FR culture on thread 3.
//         163 025 412,32 €   18 905 365,59 €
//
//         Executing a task synchronously:
//         Formatting using the fr-FR culture on thread 1.
//         163 025 412,32 €   18 905 365,59 €

DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture são propriedades de domínio por aplicativo; ou seja, estabelecem uma cultura padrão para todos os threads não atribuídos explicitamente a uma cultura em um domínio de aplicativo específico. No entanto, para aplicativos destinados ao .NET Framework 4.6 ou posterior, a cultura do thread de chamada permanece parte do contexto de uma tarefa assíncrona, mesmo que a tarefa ultrapasse os limites de domínio do aplicativo.

Serialização de objeto CultureInfo

Quando um objeto CultureInfo é serializado, tudo o que é realmente armazenado é Name e UseUserOverride. Ele é desserializado com êxito apenas em um ambiente em que esse Name tem o mesmo significado. Os três exemplos a seguir mostram por que nem sempre esse é o caso:

  • Se o valor da propriedade CultureTypes for CultureTypes.InstalledWin32Cultures, e se essa cultura tiver sido introduzida pela primeira vez em uma versão específica do sistema operacional Windows, não será possível desserializá-lo em uma versão anterior do Windows. Por exemplo, se uma cultura foi introduzida no Windows 10, ela não pode ser desserializada no Windows 8.

  • Se o valor CultureTypes for CultureTypes.UserCustomCulture, e o computador no qual ele está desserializado não tiver essa cultura personalizada do usuário instalada, não será possível desserializá-lo.

  • Se o valor CultureTypes for CultureTypes.ReplacementCultures, e o computador no qual ele está desserializado não tiver essa cultura de substituição, ele desserializa para o mesmo nome, mas não todas as mesmas características. Por exemplo, se en-US for uma cultura de substituição no computador A, mas não no computador B, e se um objeto CultureInfo que se refere a essa cultura for serializado no computador A e desserializado no computador B, nenhuma das características personalizadas da cultura será transmitida. A cultura desserializa com êxito, mas com um significado diferente.

Substituições do Painel de Controle

O usuário pode optar por substituir alguns dos valores associados à cultura atual do Windows por meio das opções de idioma e região do Painel de Controle. Por exemplo, o usuário pode optar por exibir a data em um formato diferente ou usar uma moeda diferente do padrão para a cultura. Em geral, seus aplicativos devem respeitar essas substituições de usuário.

Se UseUserOverride for true e a cultura especificada corresponder à cultura atual do Windows, CultureInfo usará essas substituições, incluindo as configurações de usuário para as propriedades da instância DateTimeFormatInfo retornadas pela propriedade DateTimeFormat e as propriedades da instância NumberFormatInfo retornadas pela propriedade NumberFormat. Se as configurações do usuário forem incompatíveis com a cultura associada ao CultureInfo, por exemplo, se o calendário selecionado não for um dos OptionalCalendars, os resultados dos métodos e os valores das propriedades serão indefinidos.

Ordens de classificação alternativas

Algumas culturas dão suporte a mais de uma ordem de classificação. Por exemplo:

  • A cultura espanhola (Espanha) tem duas ordens de classificação: a ordem de classificação internacional padrão e a ordem de classificação tradicional. Quando você cria uma instância de um CultureInfo objeto com o nome da cultura es-ES, a ordem de classificação internacional é usada. Quando você cria uma instância de um objeto CultureInfo com o nome da cultura es-ES-tradnl, a ordem de classificação tradicional é usada.

  • A cultura zh-CN (chinês (simplificado, PRC)) dá suporte a duas ordens de classificação: por pronúncia (o padrão) e por contagem de traços. Quando você cria uma instância de um objeto CultureInfo com o nome de cultura zh-CN, a ordem de classificação padrão é usada. Quando você cria uma instância de um objeto CultureInfo com um identificador local 0x00020804, as cadeias de caracteres são classificadas por contagem de traços.

A tabela a seguir lista as culturas que dão suporte a ordens de classificação alternativas e aos identificadores para os pedidos de classificação padrão e alternativos.

Nome da cultura Cultura Nome e identificador de classificação padrão Nome e identificador de classificação alternativos
es-ES Espanhol (Espanha) Internacional: 0x00000C0A Tradicional: 0x0000040A
zh-TW Chinês (Taiwan) Contagem de traços: 0x00000404 Bopomofo: 0x00030404
zh-CN Chinês (China) Pronúncia: 0x00000804 Contagem de traços: 0x00020804
zh-HK Chinês (RAE de Hong Kong) Contagem de traços: 0x00000c04 Contagem de traços: 0x00020c04
zh-SG Chinês (Singapura) Pronúncia: 0x00001004 Contagem de traços: 0x00021004
zh-MO Chinese (Macao SAR) Pronúncia: 0x00001404 Contagem de traços: 0x00021404
ja-JP Japonês (Japão) Padrão: 0x00000411 Unicode: 0x00010411
ko-KR Coreano (Coreia do Sul) Padrão: 0x00000412 Xwansung coreano – Unicode: 0x00010412
de-DE Alemão (Alemanha) Dicionário: 0x00000407 Classificação da lista telefônica DIN: 0x00010407
hu-HU Húngaro (Hungria) Padrão: 0x0000040e Classificação técnica: 0x0001040e
ka-GE Georgiano (Geórgia) Tradicional: 0x00000437 Classificação moderna: 0x00010437

A cultura e os aplicativos UWP atuais

Em aplicativos da Plataforma Universal do Windows (UWP), as propriedades CurrentCulture e CurrentUICulture são de leitura/gravação, assim como em aplicativos .NET Framework e .NET Core. No entanto, os aplicativos UWP reconhecem uma única cultura. As propriedades CurrentCulture e CurrentUICulture são mapeadas para o primeiro valor na coleção Windows.ApplicationModel.Resources.Core.ResourceManager.DefaultContext.Languages.

Em aplicativos .NET, a cultura atual é uma configuração por thread e as propriedades CurrentCulture e CurrentUICulture refletem a cultura e a cultura da interface do usuário apenas do thread atual. Em aplicativos da UWP, a cultura atual é mapeada para a coleção Windows.ApplicationModel.Resources.Core.ResourceManager.DefaultContext.Languages, que é uma configuração global. Definir a propriedade CurrentCulture ou CurrentUICulture altera a cultura de todo o aplicativo; a cultura não pode ser definida por thread.