Por que o separador de grupo de número de cultura .NET “de-CH” é diferente localmente e no Azure?
Estou vendo um caractere Unicode diferente como o separador de grupo de números para a cultura "de-CH" ao executar em uma área de trabalho local e no Azure.
Quando o código a seguir é executado em minha área de trabalho no .NET Core 3.1 ou .NET Framework 4.7.2, a saída 2019
é semelhante a um apóstrofo, mas não é o mesmo.
Quando executado no Azure, por exemplo em https://try.dot.netou (ligeiramente modificado) em uma função do Azure em execução no .NET Core 3.1 (em um Serviço de Aplicativo baseado no Windows) resulta em 0027
um apóstrofo ASCII padrão.
using System;
using System.Linq;
using System.Globalization;
Console.WriteLine(((int)(CultureInfo
.GetCultureInfo("de-CH")
.NumberFormat
.NumberGroupSeparator
.Single())) // Just getting the single character as an int
.ToString("X4") // unicode value of that character
);
O resultado disso é que a tentativa de analisar a string 4'200.000
(onde o apóstrofo é Unicode 0027
) na área de trabalho local usando a cultura "de-CH" falha, mas funciona no Azure.
Por que a diferença?
Respostas
Este blog da Microsoft por Shawn Steele explica por que você não deve confiar que uma configuração de cultura específica seja estável (totalmente citado porque não está mais online no MSDN):
https://web.archive.org/web/20190110065542/https://blogs.msdn.microsoft.com/shawnste/2005/04/05/culture-data-shouldnt-be-considered-stable-except-for-invariant/
Os dados CultureInfo e RegionInfo representam uma preferência cultural, regional, administrativa ou do usuário para configurações culturais. Os aplicativos NÃO devem fazer suposições que dependem da estabilidade dos dados. A única exceção (esta é uma regra, então é claro que há uma exceção) é para CultureInfo.InvariantCulture. CultureInfo.InvariantCulture deve permanecer estável, mesmo entre as versões.
Existem muitos motivos pelos quais os dados culturais podem mudar. Com Whidbey e Custom Cultures, a lista fica um pouco mais longa.
- A razão mais óbvia é que há um bug nos dados e tivemos que fazer uma alteração. (Acredite ou não, cometemos erros ;-)) Neste caso, nossos usuários (e os seus também) querem dados culturalmente corretos, então temos que consertar o bug mesmo se ele quebrar os aplicativos existentes.
- Outra razão é que as preferências culturais podem mudar. Isso pode acontecer de várias maneiras, mas acontece:
- Consciência global, intercâmbio cultural, a mudança do papel dos computadores e assim por diante podem afetar uma preferência cultural.
- Tratados internacionais, comércio, etc. podem alterar valores. A adoção do Euro mudou o símbolo da moeda de muitos países para €.
- Regulamentações nacionais ou regionais também podem afetar esses valores.
- A grafia preferida das palavras pode mudar com o tempo.
- Os formatos de data preferidos, etc. podem mudar.
- Podem existir várias preferências para uma cultura. A melhor escolha preferida pode então mudar com o tempo.
- Os usuários podem ter substituído alguns valores, como formatos de data ou hora. Eles podem ser solicitados sem substituição do usuário, no entanto, recomendamos que os aplicativos considerem o uso de substituições do usuário.
- Os usuários ou administradores podem ter criado uma cultura de substituição, substituindo os valores padrão comuns de uma cultura por específicos da empresa, específicos da região ou outras variações dos dados padrão.
- Algumas culturas podem ter preferências que variam dependendo da configuração. Uma empresa pode ter uma forma mais formal do que um Internet Café.
- Uma empresa pode exigir um formato de data ou hora específico para toda a organização.
- Versões diferentes da mesma cultura customizada, ou uma que é customizada em uma máquina e uma cultura apenas do Windows em outra máquina.
Portanto, se você formatar uma string com um formato de data / hora específico e tentar analisá-la mais tarde, a análise pode falhar se a versão for alterada, se a máquina for alterada, se a versão da estrutura for alterada (dados mais recentes) ou se uma cultura personalizada foi alterado. Se você precisa manter os dados em um formato confiável, escolha um método binário, forneça seu próprio formato ou use o InvariantCulture.
Mesmo sem alterar os dados, lembrar de usar o Invariant ainda é uma boa ideia. Se você tiver diferente. e sintaxe para algo como 1.000,29, então a análise pode ficar confusa se um cliente esperava 1.000,29. Já vi esse problema com aplicativos que não percebiam que a cultura do usuário seria diferente da cultura do desenvolvedor. O uso de invariante ou outra técnica resolve esse tipo de problema.
É claro que você não pode ter uma exibição "correta" para o usuário atual e uma viagem de ida e volta perfeita se os dados de cultura forem alterados. Então, geralmente eu recomendo persistir os dados usando InvariantCulture ou outro formato imutável e sempre usando as APIs de formatação apropriadas para exibição. Seu aplicativo terá seus próprios requisitos, portanto, considere-os com cuidado.
Observe que, para agrupamento (ordem de classificação / comparações), mesmo o comportamento Invariante pode mudar. Você precisará usar o controle de versão de classificação para contornar isso se precisar de ordens de classificação consistentemente estáveis.
Se você precisar analisar dados automaticamente formatados para serem fáceis de usar, há duas abordagens:
- Permitir que o usuário especifique explicitamente o formato usado.
- Remova primeiro todos os caracteres, exceto os dígitos, o sinal de menos e o separador decimal da string antes de tentar analisar isso. Observe que você precisa saber primeiro o separador decimal correto. Não há como adivinhar isso corretamente e adivinhar errado pode resultar em grandes problemas.
Sempre que possível, tente evitar a análise de números formatados para serem fáceis de usar. Em vez disso, sempre que possível, tente solicitar números em um formato estritamente definido (invariável).