.NET 5.0的string.Contais
和string.IndexOf
的坑。
不知道干什么的话,用StringComparison.Ordinal
就对了。
新建一个net5程序,运行以下代码:
using System;
class Program
{
public static void Main()
{
Console.WriteLine("Hello\r\nWorld".Contains("\nW"));
Console.WriteLine("Hello\r\nWorld".IndexOf("\nW"));
}
}
我们可以看到,这段代码输出的结果是
True
-1
好像有什么不对…
为什么明明包含但是IndexOf
找不到而Contains
还是True的!
更多测试
Windows 10 20H2 Build 19042.685, en-CA (LCID 4105) | fx | mono | core3 | net5 |
---|---|---|---|---|
"encyclopædia".Contains("ae") "encyclopædia".IndexOf("ae") |
False 8 |
False 8 |
False 8 |
False -1 |
"Hello\r\nWorld".Contains("\n") "Hello\r\nWorld".IndexOf("\n") |
True 6 |
True 6 |
True 6 |
True-1 |
"Hello\r\nWorld".Contains('\n') "Hello\r\nWorld".IndexOf('\n') |
True 6 |
True 6 |
True 6 |
True-1 |
"encyclopædia".Contains("ae", StringComparison.Ordinal) "encyclopædia".IndexOf("ae", StringComparison.Ordinal) |
-1 |
False -1 |
False -1 |
False-1 |
"Hello\r\nWorld".Contains("\n", StringComparison.Ordinal) "Hello\r\nWorld".IndexOf("\n", StringComparison.Ordinal) |
6 |
True 6 |
True 6 |
True 6 |
"Hello\r\nWorld".Contains('\n', StringComparison.Ordinal) "Hello\r\nWorld".IndexOf('\n', StringComparison.Ordinal) |
True 6 |
True 6 |
True 6 |
|
"encyclopædia".Contains("ae", StringComparison.InvariantCulture) "encyclopædia".IndexOf("ae", StringComparison.InvariantCulture) |
8 |
True 8 |
True8 |
False -1 |
"Hello\r\nWorld".Contains("\n", StringComparison.InvariantCulture) "Hello\r\nWorld".IndexOf("\n", StringComparison.InvariantCulture) |
6 |
True 6 |
True 6 |
False -1 |
"Hello\r\nWorld".Contains('\n', StringComparison.InvariantCulture) "Hello\r\nWorld".IndexOf('\n', StringComparison.InvariantCulture) |
True 6 |
True 6 |
False -1 |
fx平台下的部分string.Contains
和string.IndexOf
没有对应的重载,因此无结果
看起来更不对了…
为什么不光有True -1
的组合,还有好几个NET5变了的结果啊!
ICU和NLS
.NET比较语言用的是platform dependent的本机代码(native)库。在Windows下,这个功能是由NLS(National Language Support)提供的,而在其他平台则是ICU(International Components for Unicode)提供的。
自从.NET 5开始,在Windows下也开始使用ICU - 所以NLS和ICU的不同行为导致了一部分的变化…
例如说,"\r\n".IndexOf("\n")
是-1。
那是因为根据设定,相邻的<CR><LF>
不可分割,所以这个\n
不能单独拿出来说
思考 那为什么Contains又可以?
因为string.Contains(string)
默认对比的是二进制(StringComparison.Ordinal
)
顺便,fx是没有string.Contains(char)
的,你试图这么做的话会得到IEnumerable<char>.Contains(char)
string.Contains(string)
和string.Contains(char)
默认是StringComparison.Ordinal
string.IndexOf(string)
默认是StringComparison.CurrentCulture
小结
不知道干什么的话,指定StringComparison.Ordinal
就对了。
至少,当你在用IndexOf
来搜索字符串中的\n
时,加别的选项或不加不一定能找到,但加上这个选项总能找到(如果有的话)。
References
MSDN: Behavior changes when comparing strings on .NET 5+ / MSDN: 在 .NET 5 及更高版本中比较字符串时的行为更改