编辑:我最初认为这与 .NET Framework 4.5 有关。原来它也适用于 .NET Framework 4.0。
Windows Server 2012 中字符串的处理方式发生了变化,我试图更好地理解这一点。StartsWith 的行为似乎发生了变化。使用 .NET Framework 4.0 和 4.5 可以重现该问题。
在 Windows 7 上使用 .NET Framework 4.5,下面的程序会打印“False, t”。在 Windows 2012 Server 上,它改为打印“True, t”。
internal class Program
{
private static void Main(string[] args)
{
string byteOrderMark = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
Console.WriteLine("test".StartsWith(byteOrderMark));
Console.WriteLine("test"[0]);
}
}
换句话说,无论字符串内容如何,StartsWith(ByteOrderMark) 都会返回 true。如果您的代码尝试使用以下方法去除字节顺序标记,则此代码在 Windows 7 上可以正常工作,但在 Windows 2012 上将打印“est”。
internal class Program
{
private static void Main(string[] args)
{
string byteOrderMark = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
string someString = "Test";
if (someString.StartsWith(byteOrderMark))
someString = someString.Substring(1);
Console.WriteLine("{0}", someString);
Console.ReadKey();
}
}
我意识到如果您在字符串中有字节顺序标记,那么您已经做错了,但是我们正在与具有此功能的遗留代码集成。我知道我可以通过执行以下操作来解决这个特定问题,但我想更好地理解这个问题。
someString = someString.Trim(byteOrderMark[0]);
Hans Passsant 建议使用 UTF8Encoding 的构造函数,它可以让我明确告诉它发出 UTF8 标识符。我试过这个,但它给出了相同的结果。下面的代码在 Windows 7 和 Windows Server 2012 之间的输出不同。在 Windows 7 上,它打印“结果:假”。在 Windows Server 2012 上,它会打印“结果:真”。
private static void Main(string[] args)
{
var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
string byteOrderMark = encoding.GetString(encoding.GetPreamble());
Console.WriteLine("Result: " + "Hello".StartsWith(byteOrderMark));
Console.ReadKey();
}
我还尝试了以下变体,它在 Windows 7 上打印 False、False、False,但在 Windows Server 2012 上打印 True、True、False,这证实它与 Windows Server 2012 上的 StartsWith 实现有关。
private static void Main(string[] args)
{
var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
string byteOrderMark = encoding.GetString(encoding.GetPreamble());
Console.WriteLine("Hello".StartsWith(byteOrderMark));
Console.WriteLine("Hello".StartsWith('\ufeff'.ToString()));
Console.WriteLine("Hello"[0] == '\ufeff');
Console.ReadKey();
}