c# - usar - Error en la comparación de cadenas del.NET Framework
string.equals c# (2)
Me encontré con esta publicación de SO, mientras trataba de descubrir por qué estaba teniendo problemas para recuperar (cadena) las claves que se insertaron en una SortedList, después de descubrir que la causa era el comportamiento extraño de .Net 40 y comparadores anteriores (a1 <a2 y a2 <a3, pero a1> a3).
Mi lucha para descubrir qué estaba pasando se puede encontrar aquí: c # SortedList <string, TValue> .ContainsKey para la clave agregada exitosamente devuelve false .
Es posible que desee echar un vistazo a la sección "ACTUALIZAR 3" de mi pregunta SO. Parece que el problema se informó a Microsoft en diciembre de 2012 y se cerró antes de finales de enero de 2013 como "no se solucionará". Además, enumera una solución alternativa que se puede utilizar.
Creé una implementación de esta solución alternativa recomendada y verifiqué que solucionaba el problema que había encontrado. También comprobé que esto resuelve el problema que informaste.
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
}
El problema restante es que esta solución es tan lenta que no es práctica para su uso con grandes colecciones de cadenas. Así que espero que Microsoft reconsidere el cierre de este problema o que alguien sepa de una mejor solución.
Es un requisito para cualquier clase de comparación que el operador de orden subyacente sea transitivo y antisimétrico .
En .NET, eso no es cierto para algunas cadenas:
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
}
Ves que x
es estrictamente mayor que y
, y y
es estrictamente mayor que x
.
Debido a que x.CompareTo(x)
y así sucesivamente todos dan cero ( 0
), está claro que esto no es un orden. No es sorprendente que obtenga resultados impredecibles cuando Sort
matrices o listas que contienen cadenas como x
e y
. Aunque no he probado esto, estoy seguro de que SortedDictionary<string, WhatEver>
tendrá problemas para mantenerse ordenado y / o ubicar elementos si se usan cadenas como x
para claves.
¿Este error es bien conocido? ¿Qué versiones del framework están afectadas (estoy intentando esto con .NET 4.0)?
EDITAR:
Aquí hay un ejemplo donde el signo es negativo de cualquier manera:
x = "/u4E00/u30A0"; // equiv: "一゠"
y = "/u4E00/u002D/u0041"; // equiv: "一-A"
Si la clasificación correcta es tan importante en su problema, simplemente use la comparación de cadena ordinal en lugar de sensible al cultivo. Solo este garantiza la comparación transitiva y antisimétrica que desee.
Especificar el valor StringComparison.Ordinal o StringComparison.OrdinalIgnoreCase en una llamada a método significa una comparación no lingüística en la que se ignoran las características de los lenguajes naturales. Los métodos que se invocan con estos valores de StringComparison basan las decisiones de operación de cadenas en comparaciones de bytes simples en lugar de tablas de mayúsculas o equivalencias que se parametrizan por cultura. En la mayoría de los casos, este enfoque se ajusta mejor a la interpretación prevista de las cadenas de caracteres a la vez que hace que el código sea más rápido y más confiable.
Y funciona como se esperaba:
Console.WriteLine(String.Compare(x, y, StringComparison.Ordinal)); // -12309
Console.WriteLine(String.Compare(y, x, StringComparison.Ordinal)); // 12309
Sí, no explica por qué la comparación sensible a la cultura arroja resultados inconsistentes. Bueno, cultura extraña, resultado extraño.