这个c#代码足以应对全球化吗?

时间:2015-03-28 11:57:37

标签: c# .net sql-server datetime

我的C#winforms计划将在以下国家/地区使用

United Kingdom  : date format day-month-year , currency separator is '.'
United States   : date format month-day-year , currency separator is '.'
Denmark         : date format day-month-year , currency separator is ','

无论用户计算机上的区域设置如何,我都希望程序正常运行。我主要关注的是处理日期格式和货币字段 (语言翻译不是问题,因为程序只会显示英文文本)

为此,我决定数据库中的所有日期将以yyyy-mm-dd格式保存,所有小数字段将以.作为分隔符保存。
我使用Danish_Norwegian_CI_AS排序规则创建了数据库。 所以我假设数据将以上述datetime格式保存。十进制格式,没有我要求做任何特殊的事情。

我已在程序中添加以下代码

var cult = new CultureInfo("en-GB");
Thread.CurrentThread.CurrentCulture = cult;
Thread.CurrentThread.CurrentUICulture = cult;

CultureInfo.DefaultThreadCurrentCulture = cult;
CultureInfo.DefaultThreadCurrentUICulture = cult;

请根据您的经验告诉我上述代码是否足以使我的程序安全

1 个答案:

答案 0 :(得分:2)

文化仅在以下两种情况下应用

  • 将值的字符串表示形式转换为本机格式,称为"解析"。

  • 将值的原生格式转换为字符串表示形式,称为"格式化"。

datetimedecimal或其他类型存储到数据库中时,它将以本机格式存储。在SQL数据库中,这通常是一些您永远不会直接使用的紧凑二进制值。

考虑以下SQL:

declare @dt datetime
set @dt = '01/02/2015 12:34:56'
select @dt

在第一行中,我们声明了一个datetime类型的变量。它不是一个字符串,它是一个占用8个字节内存或磁盘的特定数据类型。

在第二行中,我们为变量分配一个字符串值。 SQL 解析字符串,将其转换为datetime,以便将其存储在@dt变量中。存储的实际值具有0x0000A41400CF5940的十六进制表示。

在进行解析时,应用了运行代码的环境的当前文化。因为我在美国,它将日期解释为1月2日。如果我在欧洲,它会将日期解释为2月1日(将内部值更改为0x0000A43200CF5940)。

使用yyyy-mm-dd格式的日期可避免误解,但这并不意味着实际值存储为该格式的字符串。只是格式是明确的,所以无论文化如何,它都将以相同的方式解析

在上面的第三行代码中,我们选择变量以将其包含在结果集中。虽然我们在没有任何转换的情况下以原生形式选择它,但我们最终以字符串表示形式查看它。如果在SQL Server Management Studio等工具中运行查询,则输出窗口将格式化本地值为字符串,以便您可以读取它们。这样做时,再次应用当前的文化。 SQL的默认设置是以yyyy-mm-dd格式显示日期,而不是特定于文化的格式。但是其他值(例如小数)将使用当前文化的分隔符。

如果不是在SSMS中运行它,而是通过SqlDataReader中的自己的代码实际检索结果(例如),那么格式化永远不会发生。读者使用the mappings shown here将SQL的二进制本机值直接映射到适当的.NET本机类型。 SQL datetime本机映射到.NET DateTime

DateTime dt = (DateTime) reader["dt"];

现在很多时候,你会看到有人做这样愚蠢的事情:

DateTime dt = Convert.ToDateTime(reader["dt"].ToString());

这很浪费,因为值已经一个DateTime,并且此代码将使用当前区域性格式化字符串,然后再次使用它来解析字符串。无缘无故地进行了大量的字符串操作。

最终,在您的.NET代码中,您将最终使用该DateTime值并将其转换为某个字符串以进行输出。当你这样做时,当你应用当前文化时

同样,当您收到用户的输入字符串时(例如填写表单时),您再次使用当前文化将值解析为DateTime

原生数据类型不是字符串 - 因此不受文化影响。

注意:

  • 如果要查看任何SQL数据类型的本机二进制形式的十六进制表示形式,可以使用以下内容:select convert(varbinary, @dt)

  • 请注意您工作的任何地方的原生格式。如果您正在写入http流,文本文件或文档数据库等,字符串表示确实确实很重要,因为字符串 这些场景中的原生格式。

为了证明这不仅适用于日期,请考虑:

select 123, 123.45, convert(varbinary, 123), convert(varbinary, 123.45)

--results:    123    123.45    0x0000007B    0x0502000139300000