string.IndexOf returns .NET 5.0 中的不同值

string.IndexOf returns different value in .NET 5.0

当我在 .NET Core 3.1 中 运行 以下代码时,我得到 6 作为 return 值。

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

结果:

6

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

// .NET 5.0
string s = "Hello\r\nworld!";
int idx = s.IndexOf("\n");
Console.WriteLine(idx);

结果:

-1

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

In the past, the .NET globalization APIs used different underlying libraries on different platforms. On Unix, the APIs used International Components for Unicode (ICU), and on Windows, they used National Language Support (NLS). [...] Behavior differences were evident in these areas:

  • Cultures and culture data
  • String casing
  • String sorting and searching
  • Sort keys
  • String normalization
  • Internationalized Domain Names (IDN) support
  • Time zone display name on Linux

To revert back to using NLS [as relevant for Windows 10 May 2019 Update and newer which now uses ICU by default], a developer can opt out of the ICU implementation. Applications can enable NLS mode in any of the following ways:

  • In the project file:

    <ItemGroup>
      <RuntimeHostConfigurationOption Include="System.Globalization.UseNls" Value="true" />
    </ItemGroup>
    
  • In the runtimeconfig.json file:

    {
      "runtimeOptions": {
         "configProperties": {
           "System.Globalization.AppLocalIcu": "<suffix>:<version> or <version>"
         }
      }
    }
    
  • By setting the environment variable DOTNET_SYSTEM_GLOBALIZATION_APPLOCALICU to the value <suffix>:<version> or <version>.

    <suffix>: Optional suffix of fewer than 36 characters in length, following the public ICU packaging conventions. When building a custom ICU, you can customize it to produce the lib names and exported symbol names to contain a suffix, for example, libicuucmyapp, where myapp is the suffix.

    <version>: A valid ICU version, for example, 67.1. This version is used to load the binaries and to get the exported symbols.

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

不过,我也建议您继续阅读 ,因为您一开始只需要担心这些来自不精确字符串操作的细节。

评论和@Ray的回答都有原因。

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

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

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

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

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