当字符串保证不会改变时,字符串比较真的可以根据文化而有所不同吗?

B. *_*non 54 c# resharper cultureinfo configuration-files string-comparison

我正在从配置文件中读取加密的凭证/连接字符串.Resharper告诉我,"String.IndexOf(string)在这里是特定于文化的"这一行:

if (line.Contains("host=")) {
    _host = line.Substring(line.IndexOf(
        "host=") + "host=".Length, line.Length - "host=".Length);
Run Code Online (Sandbox Code Playgroud)

......所以想把它改成:

if (line.Contains("host=")) {
    _host = line.Substring(line.IndexOf("host=", System.StringComparison.Ordinal) + "host=".Length, line.Length -   "host=".Length);
Run Code Online (Sandbox Code Playgroud)

无论应用程序在何处部署,我正在阅读的值始终为"host =".添加这个"System.StringComparison.Ordinal"位是否真的明智?

更重要的是,它可以伤害任何东西(使用它)吗?

Mar*_*wul 65

绝对.根据MSDN(http://msdn.microsoft.com/en-us/library/d93tkzah.aspx),

此方法使用当前文化执行单词(区分大小写和文化敏感)搜索.

因此,如果您在不同的文化下运行它(通过控制面板中的区域和语言设置),您可能会得到不同的结果.

在这种特殊情况下,你可能不会有问题,但是i在搜索字符串中输入并在土耳其运行它可能会毁了你的一天.

请参阅MSDN:http://msdn.microsoft.com/en-us/library/ms973919.aspx

这些新的建议和API用于缓解有关默认字符串API行为的错误假设.在语言上解释非语言字符串数据时出现的错误的典型示例是"土耳其语I"问题.

对于几乎所有拉丁字母,包括美国英语,字符i(\ u0069)是字符I(\ u0049)的小写版本.这种套管规则很快成为这种文化中某人编程的默认设置.但是,在土耳其语("tr-TR")中,存在一个大写字母"i with a dot"字符(\ u0130),它是i的大写字母.同样地,在土耳其语中,有一个小写的"我没有点"或(\ u0131),它大写为I.这种行为也发生在阿塞拜疆文化("az")中.

因此,通常关于资本化或低资本化I的假设在所有文化中都是无效的.如果使用字符串比较例程的默认重载,则它们将受到不同文化之间的差异的影响.对于非语言数据,如下例所示,这会产生不希望的结果:

    Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")
Console.WriteLine("Culture = {0}",
   Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}", 
   (String.Compare("file", "FILE", true) == 0));

Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
Console.WriteLine("Culture = {0}",
   Thread.CurrentThread.CurrentCulture.DisplayName);
Console.WriteLine("(file == FILE) = {0}", 
   (String.Compare("file", "FILE", true) == 0));
Run Code Online (Sandbox Code Playgroud)

由于I的比较不同,当线程文化发生变化时,比较结果会发生变化.这是输出:

Culture = English (United States)
(file == FILE) = True
Culture = Turkish (Turkey)
(file == FILE) = False
Run Code Online (Sandbox Code Playgroud)

这是一个没有案例的例子:

var s1 = "é"; //é as one character (ALT+0233)
var s2 = "e?"; //'e', plus combining acute accent U+301 (two characters)

Console.WriteLine(s1.IndexOf(s2, StringComparison.Ordinal)); //-1
Console.WriteLine(s1.IndexOf(s2, StringComparison.InvariantCulture)); //0
Console.WriteLine(s1.IndexOf(s2, StringComparison.CurrentCulture)); //0
Run Code Online (Sandbox Code Playgroud)

  • 好吧,忘了案子.如果你不在英语范围内,还有其他例子.例如e +组合重音,与é相比.它们在序数上是不同的,但在语言上是相同的(参见编辑).猜猜看,语言很难. (8认同)
  • 为什么IndexOf与案件有任何关系,微软正在以他们喜欢的通常臃肿的方式混合一切.他们的错误在于总是首先假设最复杂的,让我们选择低级的方式,用一种非常冗长的方式. (2认同)

m-y*_*m-y 27

CA1309:UseOrdinalStringComparison

不使用它并没有坏处,但" 通过将参数显式设置为StringComparison.Ordinal或StringComparison.OrdinalIgnoreCase,您的代码通常可以提高速度,提高正确性,并变得更加可靠. "


Ordinal到底是什么,为什么它对你的情况很重要?

使用序数排序规则的操作基于字符串中每个Char的数值(Unicode代码点)执行比较.序数比较快但对文化不敏感.当您使用序数排序规则对以Unicode字符(U +)开头的字符串进行排序时,如果xxxx的值在数字上小于yyyy,则字符串U + xxxx位于字符串U + yyyy之前.

并且,正如您所说的......您正在读取的字符串值对文化不敏感,因此使用序数比较而不是Word比较是有意义的.请记住,Ordinal意味着"这不是文化敏感的".


500*_*ror 7

回答您的具体问题:不,但静态分析工具无法实现您的输入值永远不会包含特定于语言环境的信息.