Почему средство сравнения строк по умолчанию не поддерживает транзитивную согласованность?

Я знаю эту проблемубыло отмечено ранееболее или менее кратко, но я все еще создаю этот новый поток, потому что я снова столкнулся с проблемой при написании модульного теста.

Сравнение строк по умолчанию (это зависимое от культуры сравнение с учетом регистра, которое мы получаем сstring.CompareTo(string), Comparer<string>.Default, StringComparer.CurrentCulture, string.Compare(string, string) и другие) нарушает транзитивность, когда строки содержат дефисы (или минус, я говорю о простых символах U + 002D).

Вот простое воспроизведение:

static void Main()
{
  const string a = "fk-";
  const string b = "-fk";
  const string c = "Fk";

  Console.WriteLine(a.CompareTo(b));  // "-1"
  Console.WriteLine(b.CompareTo(c));  // "-1"
  Console.WriteLine(a.CompareTo(c));  // "1"

  var listX = new List<string> { a, b, c, };
  var listY = new List<string> { c, a, b, };
  var listZ = new List<string> { b, c, a, };
  listX.Sort();
  listY.Sort();
  listZ.Sort();
  Console.WriteLine(listX.SequenceEqual(listY));  // "False"
  Console.WriteLine(listY.SequenceEqual(listZ));  // "False"
  Console.WriteLine(listX.SequenceEqual(listZ));  // "False"
}

В верхней части мы видим, как транзитивность терпит неудачу.a меньше чемb, а такжеb меньше чемc, ещеa не может быть меньше, чемc.

Это идет вразрез сдокументированное поведение сопоставления Unicode, в котором говорится, что:

... для любых строк A, B и C, если A <B и B <C, то A <C.

Теперь сортировка списка сa, b а такжеc точно так же, как пытаться оценить руки«Скала», «Бумага» и «Ножницы» в известной непереходной игре. Невыполнимая задача.

Последняя часть моего примера кода выше показывает, что результат сортировки зависит от начального порядка элементов (и в списке нет двух элементов, которые сравнивают «равные» (0)).

Linq-хlistX.OrderBy(x => x) Это также влияет, конечно. Это должна быть стабильная сортировка, но вы получите странные результаты при заказе коллекции, содержащейa, b а такжеc вместе с другими строками.

Я пробовал это свсе CultureInfos на моей машине (поскольку это зависит от культуры), включая «инвариантную культуру», и у каждого из них есть одна и та же проблема. Я пытался сделать это в среде выполнения .NET 4.5.1, но я считаю, что в старых версиях та же ошибка.

Вывод: при сортировке строк в .NET с помощью компаратора по умолчанию результаты непредсказуемы, если некоторые строки содержат дефисы.

Какие изменения были внесены в .NET 4.0, которые вызвали такое поведение?

Уже отмечалось, что это поведение несовместимо в разных версиях платформы: в .NET 3.5 строки с дефисами могут быть надежно отсортированы. Во всех версиях фреймворка звонитSystem.Globalization.CultureInfo.CurrentCulture.CompareInfo.GetSortKey обеспечивает уникальныйDeyData для этих строк, так почему они не отсортированы правильно?

Ответы на вопрос(1)

Ваш ответ на вопрос