string.IndexOf 在 .NET 5.0 中返回不同的值

Far*_*ani 12 c# .net-core .net-5

当我在 .NET Core 3.1 中运行以下代码时,我得到6了返回值。

// .NET Core 3.1
string s = "Hello\r\nworld!";
int idx = s.IndexOf("\n");
Console.WriteLine(idx);
Run Code Online (Sandbox Code Playgroud)

结果:

6
Run Code Online (Sandbox Code Playgroud)

但是当我在 .NET 5.0 中运行这段代码时,我得到了不同的结果。为什么会发生这种情况?

6
Run Code Online (Sandbox Code Playgroud)

结果:

-1
Run Code Online (Sandbox Code Playgroud)

Gyö*_*zeg 14

评论和@Ray 的回答包含了原因。

尽管破解.csprojorruntimeconfig.json文件可能会节省您的时间,但真正的解决方案是明确指定比较:

// this returns the expected result
int idx = s.IndexOf("\n", StringComparison.Ordinal);
Run Code Online (Sandbox Code Playgroud)

由于某些原因,IndexOf(string)默认使用当前区域性比较,当您的应用程序在与您的区域设置不同的环境中执行时,即使使用较早的 .NET 版本也可能会导致意外。

使用特定于文化的搜索实际上是一种非常罕见的场景(例如,可以在浏览器、图书阅读器或 UI 搜索中有效)并且它比顺序搜索慢得多。

同样的问题也适用于StartsWith/ EndsWith/ Contains/ ToUpper/ToLower甚至ToStringParseformattable类型的方法(尤其是使用浮点类型时),因为这些也默认使用当前的文化,这可以有很多陷阱的来源。但是,如果您不使用特定的比较或文化,最近的代码分析器(例如 FxCop、ReSharper)会警告您。建议在产品代码中为这些问题设置高严重性。


Ray*_*Ray 5

您的示例代码与MSDN上发布的代码完全匹配,该代码还描述了为什么以及如何在这些摘录中恢复到旧行为(重点是我的):

过去,.NET 全球化 API 在不同平台上使用不同的底层库。在 Unix 上,API 使用Unicode 国际组件 (ICU),而在 Windows 上,它们使用国家语言支持 (NLS)。[...]这些领域的行为差异很明显

  • 文化和文化数据
  • 字符串套管
  • 字符串排序和搜索
  • 排序键
  • 字符串规范化
  • 国际化域名 (IDN) 支持
  • Linux 上的时区显示名称

要恢复使用 NLS [与 Windows 2019 年 5 月 10 日更新和更新版本相关,现在默认使用 ICU ],开发人员可以选择退出 ICU 实施。应用程序可以通过以下任一方式启用 NLS 模式:

  • 在项目文件中:

    <ItemGroup>
      <RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
    </ItemGroup>
    
    Run Code Online (Sandbox Code Playgroud)
  • runtimeconfig.json文件中:

    {
      "runtimeOptions": {
         "configProperties": {
           "System.Globalization.AppLocalIcu": "<suffix>:<version> or <version>"
         }
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 通过将环境变量DOTNET_SYSTEM_GLOBALIZATION_APPLOCALICU设置为值<suffix>:<version><version>.

    <suffix>: 长度少于 36 个字符的可选后缀,遵循公共 ICU 打包约定。在构建自定义 ICU 时,您可以对其进行自定义以生成 lib 名称和导出的符号名称以包含后缀,例如 libicuucmyapp,其中 myapp 是后缀。

    <version>:有效的 ICU 版本,例如 67.1。此版本用于加载二进制文件并获取导出的符号。

有关更多/最新信息,请参阅上面的 MSDN 链接。

但是,我建议您也阅读György K?szeg 的回答,因为您只需从不精确的字符串操作开始担心这些细节。