Pregunta

Comparar cadenas en C# es bastante simple.De hecho hay varias maneras de hacerlo.He enumerado algunos en el bloque a continuación.Lo que tengo curiosidad son las diferencias entre ellos y cuándo se debe utilizar uno sobre los demás.¿Deberíamos evitarlo a toda costa?¿Hay más que no he enumerado?

string testString = "Test";
string anotherString = "Another";

if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}

(Nota:Estoy buscando igualdad en este ejemplo, ni menor ni mayor que, pero no dudes en comentar sobre eso también)

¿Fue útil?

Solución

Estas son las reglas sobre cómo funcionan estas funciones:

stringValue.CompareTo(otherStringValue)

  1. null viene antes de una cuerda
  2. usa CultureInfo.CurrentCulture.CompareInfo.Compare, lo que significa que utilizará una comparación dependiente de la cultura.Esto podría significar que ß se comparará igual a SS en Alemania o similar

stringValue.Equals(otherStringValue)

  1. null no se considera igual a nada
  2. a menos que especifiques un StringComparison opción, utilizará lo que parece una verificación de igualdad ordinal directa, es decir ß no es lo mismo que SS, en cualquier idioma o cultura

stringValue == otherStringValue

  1. no es lo mismo que stringValue.Equals().
  2. El == El operador llama a la estática. Equals(string a, string b) método (que a su vez va a un interno EqualsHelper para hacer la comparación.
  3. Vocación .Equals() en un null la cuerda se pone null excepción de referencia, mientras que en == no es.

Object.ReferenceEquals(stringValue, otherStringValue)

Simplemente comprueba que las referencias sean las mismas, es decir.No son solo dos cadenas con el mismo contenido, estás comparando un objeto de cadena consigo mismo.


Tenga en cuenta que con las opciones anteriores que usan llamadas a métodos, hay sobrecargas con más opciones para especificar cómo comparar.

Mi consejo, si sólo desea comprobar la igualdad, es que decida si desea utilizar una comparación dependiente de la cultura o no, y luego utilice .CompareTo o .Equals, dependiendo de la elección.

Otros consejos

Desde MSDN:

"El método Compareto se diseñó principalmente para su uso en las operaciones de clasificación o alfabetización.No debe usarse cuando el propósito principal de la llamada del método es determinar si dos cadenas son equivalentes.Para determinar si dos cadenas son equivalentes, llame al método igual ".

Sugieren usar .Equals en lugar de .CompareTo cuando se busca únicamente la igualdad.No estoy seguro si hay una diferencia entre .Equals y == Para el string clase.A veces usaré .Equals o Object.ReferenceEquals en lugar de == para mis propias clases en caso de que alguien venga más adelante y redefina el == operador para esa clase.

Si alguna vez siente curiosidad acerca de las diferencias en los métodos BCL, Reflector es tu amigo :-)

Sigo estas pautas:

Coincidencia exacta: EDITAR:Anteriormente, siempre usaba el operador == según el principio de que dentro de Equals(string, string) el operador == del objeto se usa para comparar las referencias del objeto, pero parece que strA.Equals(strB) sigue siendo entre un 1% y un 11% más rápido en general que string. Es igual a (strA, strB), strA == strB y string.CompareOrdinal (strA, strB).Probé en bucle con un StopWatch en valores de cadena internos y no internos, con longitudes de cadena iguales o diferentes y tamaños variables (1B a 5 MB).

strA.Equals(strB)

Coincidencia legible por humanos (culturas occidentales, no distingue entre mayúsculas y minúsculas):

string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0

Coincidencia legible por humanos (todas las demás culturas, mayúsculas y minúsculas/acento/kana/etc. definidos por CultureInfo):

string.Compare(strA, strB, myCultureInfo) == 0

Coincidencia legible por humanos con reglas personalizadas (todas las demás culturas):

CompareOptions compareOptions = CompareOptions.IgnoreCase
                              | CompareOptions.IgnoreWidth
                              | CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0

Como Ed Dicho esto, CompareTo se usa para ordenar.

Sin embargo, existe una diferencia entre .Equals y ==.

== resuelve esencialmente el siguiente código:

if(object.ReferenceEquals(left, null) && 
   object.ReferenceEquals(right, null))
    return true;
if(object.ReferenceEquals(left, null))
    return right.Equals(left);
return left.Equals(right);

La sencilla razón es que lo siguiente generará una excepción:

string a = null;
string b = "foo";

bool equal = a.Equals(b);

Y lo siguiente no lo hará:

string a = null;
string b = "foo";

bool equal = a == b;

En el artículo se pueden encontrar buenas explicaciones y prácticas sobre problemas de comparación de cadenas. Nuevas recomendaciones para el uso de cadenas en Microsoft .NET 2.0 y también en Mejores prácticas para usar cadenas en .NET Framework.


Cada uno de los métodos mencionados (y otros) tiene un propósito particular.La diferencia clave entre ellos es qué tipo de Enumeración de comparación de cadenas están usando por defecto.Hay varias opciones:

  • Cultura actual
  • CulturaActualIgnorarCaso
  • Cultura Invariante
  • InvarianteCulturaIgnorarCaso
  • Ordinal
  • OrdinalIgnorarCaso

Cada uno de los tipos de comparación anteriores apunta a un caso de uso diferente:

  • Ordinal
    • Identificadores internos que distinguen entre mayúsculas y minúsculas
    • Identificadores que distinguen entre mayúsculas y minúsculas en estándares como XML y HTTP
    • Configuraciones relacionadas con la seguridad que distinguen entre mayúsculas y minúsculas
  • OrdinalIgnorarCaso
    • Identificadores internos que no distinguen entre mayúsculas y minúsculas
    • Identificadores que no distinguen entre mayúsculas y minúsculas en estándares como XML y HTTP
    • Rutas de archivos (en Microsoft Windows)
    • Claves/valores de registro
    • Variables de entorno
    • Identificadores de recursos (nombres de identificadores, por ejemplo)
    • Configuraciones relacionadas con la seguridad que no distinguen entre mayúsculas y minúsculas
  • Cultura invariante o Cultura invarianteIgnorar caso
    • Algunos datos lingüísticamente relevantes persistieron
    • Visualización de datos lingüísticos que requieren un orden de clasificación fijo
  • CurrentCulture o CurrentCultureIgnoreCase
    • Datos mostrados al usuario.
    • La mayoría de las entradas del usuario

Tenga en cuenta que Enumeración de comparación de cadenas así como sobrecargas para métodos de comparación de cadenas, existe desde .NET 2.0.


Método String.CompareTo (Cadena)

¿Es de hecho una implementación segura de tipos? Método IComparable.CompareTo.Interpretación predeterminada:Cultura actual.

Uso:

El método CompareTo fue diseñado principalmente para su uso en operaciones de clasificación o alfabetización.

De este modo

La implementación de la interfaz IComparable necesariamente utilizará este método

Método String.Compare

Un miembro estático de Clase de cadena que tiene muchas sobrecargas.Interpretación predeterminada:Cultura actual.

Siempre que sea posible, debe llamar a una sobrecarga del método Compare que incluya un parámetro StringComparison.

Método String.Equals

Anulado de la clase de objeto y sobrecargado para seguridad de tipos.Interpretación predeterminada:Ordinal.Darse cuenta de:

Los métodos de igualdad de la clase String incluyen el estática es igual, el operador estático ==, y el método de instancia es igual.


Clase StringComparer

También hay otra forma de lidiar con las comparaciones de cadenas que apunta especialmente a la clasificación:

Puedes usar el Clase StringComparer para crear una comparación de tipo específico para ordenar los elementos en una colección genérica.Clases como Hashtable, Dictionary, SortedList y SortedList utilizan la clase StringComparer para fines de clasificación.

No es que el rendimiento normalmente importe el 99% de las veces que necesitas hacer esto, pero si tuvieras que hacer esto en un bucle varios millones de veces, te sugiero que uses .Equals o == porque tan pronto como encuentre un carácter eso no coincide, descarta todo como falso, pero si usa CompareTo tendrá que determinar qué carácter es menor que el otro, lo que lleva a un tiempo de rendimiento ligeramente peor.

Si su aplicación se ejecutará en diferentes países, le recomiendo que eche un vistazo a las implicaciones de CultureInfo y posiblemente use .Equals.Como en realidad solo escribo aplicaciones para los EE. UU. (y no me importa si alguien no funciona correctamente), siempre uso ==.

En los formularios que enumeró aquí, no hay mucha diferencia entre los dos. CompareTo termina llamando a un CompareInfo método que hace una comparación utilizando la cultura actual; Equals es llamado por el == operador.

Si consideramos las sobrecargas, las cosas se ponen diferentes. Compare y == Solo se puede usar la cultura actual para comparar una cadena. Equals y String.Compare puede tomar un StringComparison Argumento de enumeración que le permite especificar comparaciones que no distinguen entre mayúsculas y minúsculas y que no distinguen entre mayúsculas y minúsculas.Solo String.Compare le permite especificar un CultureInfo y realizar comparaciones utilizando una cultura distinta a la cultura predeterminada.

Debido a su versatilidad, creo que uso String.Compare más que cualquier otro método de comparación;me permite especificar exactamente lo que quiero.

Una GRAN diferencia a tener en cuenta es que .Equals() generará una excepción si la primera cadena es nula, mientras que == no lo hará.

       string s = null;
        string a = "a";
        //Throws {"Object reference not set to an instance of an object."}
        if (s.Equals(a))
            Console.WriteLine("s is equal to a");
        //no Exception
        if(s==a)
            Console.WriteLine("s is equal to a");
  • s1.Comparar con (s2): NO lo use si el propósito principal es determinar si dos cadenas son equivalentes
  • s1 == s2: No se puede ignorar el caso
  • s1.Equals(s2, Comparación de cadenas): Lanza NullReferenceException si s1 es nulo
  • Cadena.Equals(s2, StringComparison): Por proceso de eliminación, este estático método es el GANADOR (asumiendo un caso de uso típico para determinar si dos cadenas son equivalentes).

Usar .Equals también es mucho más fácil de leer.

con .Equals, también obtienes las opciones de StringComparison.muy útil para ignorar casos y otras cosas.

Por cierto, esto se evaluará como falso.

string a = "myString";
string b = "myString";

return a==b

Dado que == compara los valores de a y b (que son punteros), esto solo se evaluará como verdadero si los punteros apuntan al mismo objeto en la memoria..Equals elimina la referencia a los punteros y compara los valores almacenados en los punteros.a.Equals(b) sería cierto aquí.

y si cambias b a:

b = "MYSTRING";

entonces a.Equals(b) es falso, pero

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

Sería verdad

a.CompareTo(b) llama a la función CompareTo de la cadena que compara los valores en los punteros y devuelve <0 si el valor almacenado en a es menor que el valor almacenado en b, devuelve 0 si a.Equals(b) es verdadero y >0 en caso contrario.Sin embargo, esto distingue entre mayúsculas y minúsculas, creo que posiblemente haya opciones para que CompareTo ignore las mayúsculas y minúsculas y demás, pero no tengo tiempo para mirar ahora.Como ya han dicho otros, esto se haría para clasificar.Comparar la igualdad de esta manera daría como resultado gastos generales innecesarios.

Estoy seguro de que estoy omitiendo cosas, pero creo que esto debería ser suficiente información para comenzar a experimentar si necesitas más detalles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top