c# – 为什么默认字符串比较器不能保持传递的一致性?

我知道这个问题has been noted before,或多或少简洁,但我仍然创建这个新线程,因为我在编写单元测试时遇到了问题。

默认字符串比较(即我们用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排序规则的documented behavior,其中规定:

… for any strings A, B, and C, if A < B and B < C, then A < C.

现在用a,b和c排序列表就像在着名的不及物游戏中排名“Rock”, “Paper” and “Scissors”的手。一个不可能的任务。

上面我的代码示例的最后一部分显示排序的结果取决于元素的初始顺序(并且在列表中没有两个元素比较“等于”(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,因此为什么它们不能正确排序?

Microsoft Connect Discussion
这里是一些代码解决方法:

static int CompareStringUsingSortKey(string s1, string s2)
{
    SortKey sk1 = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(s1);
    SortKey sk2 = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(s2);
    return SortKey.Compare(sk1, sk2);
}
http://stackoverflow.com/questions/23087995/why-does-the-default-string-comparer-fail-to-maintain-transitive-consistency

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:c# – 为什么默认字符串比较器不能保持传递的一致性?