在.NET框架的string比较中的错误

任何比较sorting都要求底层的顺序操作符是传递反对称的

在.NET中,对于某些string来说不是这样:

static void CompareBug() { string x = "\u002D\u30A2"; // or just "-ア" if charset allows string y = "\u3042"; // or just "あ" if charset allows Console.WriteLine(x.CompareTo(y)); // positive one Console.WriteLine(y.CompareTo(x)); // positive one Console.WriteLine(StringComparer.InvariantCulture.Compare(x, y)); // positive one Console.WriteLine(StringComparer.InvariantCulture.Compare(y, x)); // positive one var ja = StringComparer.Create(new CultureInfo("ja-JP", false), false); Console.WriteLine(ja.Compare(x, y)); // positive one Console.WriteLine(ja.Compare(y, x)); // positive one } 

你看到x严格大于yy严格大于x

因为x.CompareTo(x)等都给零( 0 ),这显然不是一个顺序。 毫不奇怪,我得到不可预知的结果时,我Sort数组或包含string如xy列表。 虽然我没有testing过这个,但我确定SortedDictionary<string, WhatEver>将会遇到问题,如果使用像xy这样的string作为键SortedDictionary<string, WhatEver>会保持sorting顺序和/或定位项目。

这个bug是众所周知的吗? 什么版本的框架受到影响(我正在尝试与.NET 4.0)?

编辑:

下面是一个例子,其中的符号是负面的:

 x = "\u4E00\u30A0"; // equiv: "一゠" y = "\u4E00\u002D\u0041"; // equiv: "一-A" 

我遇到这个SOpost,而我试图找出为什么我有问题检索(string)插入SortedList的键,我发现原因是.Net 40和以上比较器(a1 <a2和a2 <a3,但是a1> a3)。

我很难找出发生了什么可以在这里find: c#SortedList <string,TValue> .ContainsKey成功添加键返回false 。

你可能想看看我的SO问题的“更新3”部分。 看来,这个问题在2012年12月向微软报告,并在2013年1月底之前closures,因为“不会被修复”。 此外,它列出了可能使用的解决方法。

我创build了这个推荐的解决方法的实现,并validation它解决了我遇到的问题。 我也刚刚证实,这解决了你所报告的问题。

 public static void SO_13254153_Question() { string x = "\u002D\u30A2"; // or just "-ア" if charset allows string y = "\u3042"; // or just "あ" if charset allows var invariantComparer = new WorkAroundStringComparer(); var japaneseComparer = new WorkAroundStringComparer(new System.Globalization.CultureInfo("ja-JP", false)); Console.WriteLine(x.CompareTo(y)); // positive one Console.WriteLine(y.CompareTo(x)); // positive one Console.WriteLine(invariantComparer.Compare(x, y)); // negative one Console.WriteLine(invariantComparer.Compare(y, x)); // positive one Console.WriteLine(japaneseComparer.Compare(x, y)); // negative one Console.WriteLine(japaneseComparer.Compare(y, x)); // positive one } 

剩下的问题是,这种解决方法太慢了,对于大量的string集合来说是不实际的。 所以我希望微软会重新考虑closures这个问题,或者有人知道更好的解决方法。

如果在你的问题中正确的sorting是如此重要,只要使用序号string比较而不是文化敏感。 只有这一个保证传递和反对称比较你想要的。

MSDN说:

在方法调用中指定StringComparison.Ordinal或StringComparison.OrdinalIgnoreCase值表示忽略自然语言的特征的非语言比较。 使用这些StringComparison值调用的方法基于简单字节比较的string操作决策,而不是基于文化参数化的套pipe或等价表。 在大多数情况下,这种方法最适合string的预期解释,同时使代码更快,更可靠。

它按预期工作:

  Console.WriteLine(String.Compare(x, y, StringComparison.Ordinal)); // -12309 Console.WriteLine(String.Compare(y, x, StringComparison.Ordinal)); // 12309 

是的,这并不能解释为什么文化敏感的比较会产生不一致的结果。 那么,奇怪的文化 – 奇怪的结果。