在.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
严格大于y
, y
严格大于x
。
因为x.CompareTo(x)
等都给零( 0
),这显然不是一个顺序。 毫不奇怪,我得到不可预知的结果时,我Sort
数组或包含string如x
和y
列表。 虽然我没有testing过这个,但我确定SortedDictionary<string, WhatEver>
将会遇到问题,如果使用像x
和y
这样的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
是的,这并不能解释为什么文化敏感的比较会产生不一致的结果。 那么,奇怪的文化 – 奇怪的结果。