Подтвердить что ты не робот

Запуск с изменениями в Windows Server 2012

Изменить: изначально я думал, что это связано с .NET Framework 4.5. Оказалось, что это относится и к .NET Framework 4.0.

Там изменилось, как строки обрабатываются в Windows Server 2012, которые я пытаюсь понять лучше. Похоже, что поведение StartsWith изменилось. Эта проблема воспроизводится с использованием как .NET Framework 4.0, так и 4.5.

С .NET Framework 4.5 в Windows 7 программа ниже печатает "False, t". В Windows Server 2003 он печатает "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, но будет печатать "est" в Windows 2012.

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 он печатает "Результат: False". В Windows Server 2012 он печатает "Результат: True".

  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();
  }

Я также пробовал следующий вариант, который печатает False, False, False в Windows 7, но True, True, False в Windows Server 2012, что подтверждает его, связанное с реализацией StartsWith на Windows Server 2012.

  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();
  }
4b9b3361

Ответ 1

Оказывается, я могу воспроизвести это, запустив тестовую программу в Windows 8.1. Он находится в той же "семье", что и сервер 2012.

Наиболее вероятным источником проблемы является то, что правила сравнения с чувствительностью к культуре изменились. Они могут быть, erm, flaky и могут иметь странные результаты на этих типах персонажей. Спецификация представляет собой пространство с нулевой шириной. Признание этого требует такой же умственной гимнастики, как понимание того, почему "abc".StartsWith("") возвращает true:)

Вам нужно решить вашу проблему, используя StringComparison.Ordinal. Это произвело False, False, False:

private static void Main(string[] args) {
    var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
    string byteOrderMark = encoding.GetString(encoding.GetPreamble());
    Console.WriteLine("Hello".StartsWith(byteOrderMark, StringComparison.Ordinal));
    Console.WriteLine("Hello".StartsWith("\ufeff", StringComparison.Ordinal));
    Console.WriteLine("Hello"[0] == '\ufeff');
    Console.ReadKey();
}