Diferenças nos methods de comparação de string em C #

Comparar strings em C # é bem simples. Na verdade, existem várias maneiras de fazer isso. Eu listei alguns no bloco abaixo. O que eu estou curioso sobre são as diferenças entre eles e quando um deve ser usado sobre os outros? Alguém deve ser evitado a todo custo? Há mais que eu não listei?

string testString = "Test"; string anotherString = "Another"; if (testString.CompareTo(anotherString) == 0) {} if (testString.Equals(anotherString)) {} if (testString == anotherString) {} 

(Nota: estou procurando igualdade neste exemplo, não menor ou maior que, mas fique à vontade para comentar sobre isso também)

Aqui estão as regras para o funcionamento dessas funções:

stringValue.CompareTo(otherStringValue)

  1. null vem antes de uma string
  2. Ele usa CultureInfo.CurrentCulture.CompareInfo.Compare , o que significa que ele usará uma comparação dependente de cultura. Isso pode significar que ß será igual a SS na Alemanha, ou similar

stringValue.Equals(otherStringValue)

  1. null não é considerado igual a nada
  2. a menos que você especifique uma opção StringComparison , ela usará o que parece ser uma verificação de igualdade ordinal direta, ou seja, ß não é o mesmo que SS , em qualquer idioma ou cultura

stringValue == otherStringValue

  1. Não é o mesmo que stringValue.Equals() .
  2. O operador == chama o método estático Equals(string a, string b) (que por sua vez vai para um EqualsHelper interno para fazer a comparação.
  3. Chamar .Equals() em uma cadeia null recebe exceção de referência null , enquanto em == não.

Object.ReferenceEquals(stringValue, otherStringValue)

Apenas verifica se as referências são as mesmas, ou seja, não são apenas duas strings com o mesmo conteúdo, você está comparando um object string com ele mesmo.


Observe que com as opções acima que usam chamadas de método, há sobrecargas com mais opções para especificar como comparar.

Meu conselho, se você quer apenas verificar a igualdade, é decidir se deseja usar uma comparação dependente da cultura ou não e, em seguida, usar .CompareTo ou .Equals , dependendo da escolha.

Do MSDN:

“O método CompareTo foi projetado principalmente para uso em operações de sorting ou alfabetização. Ele não deve ser usado quando o objective principal da chamada do método é determinar se duas seqüências são equivalentes. Para determinar se duas seqüências são equivalentes, chame o método Equals. ”

Eles sugerem o uso de .Equals vez de .CompareTo ao procurar apenas pela igualdade. Não tenho certeza se existe uma diferença entre .Equals e == para a class de string . Algumas vezes utilizarei .Equals ou Object.ReferenceEquals vez de == para minhas próprias classs, caso alguém venha mais tarde e redefina o operador == para essa class.

Se você está curioso sobre as diferenças nos methods BCL, Reflector é seu amigo 🙂

Eu sigo estas diretrizes:

Correspondência exata: EDIT: Eu anteriormente sempre usei operador == no princípio de que dentro Equals (string, string) o object = = operador é usado para comparar as referências de object, mas parece que strA.Equals (strB) ainda é 1-11% mais rápido do que string.Equals (strA, strB), strA == strB e string.CompareOrdinal (strA, strB). Eu loop testado com um StopWatch em ambos os valores de seqüência de caracteres interned / non-interned, com tamanhos de seqüência de mesmo / diferente e tamanhos variados (1B a 5MB).

 strA.Equals(strB) 

Correspondência legível por humanos (culturas ocidentais, insensíveis a maiúsculas e minúsculas):

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

Correspondência legível (Todas as outras culturas, caso insensível / sotaque / kana / etc definido pelo CultureInfo):

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

Correspondência legível com regras personalizadas (todas as outras culturas):

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

Como Ed disse, CompareTo é usado para sorting.

Há uma diferença, no entanto, entre .Equals e ==.

== resolve essencialmente o seguinte 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); 

A razão simples é a seguinte irá lançar uma exceção:

 string a = null; string b = "foo"; bool equal = a.Equals(b); 

E o seguinte não irá:

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

Boas explicações e práticas sobre problemas de comparação de cadeias podem ser encontradas no artigo Novas Recomendações para o Uso de Strings no Microsoft .NET 2.0 e também em Práticas Recomendadas para Uso de Strings no .NET Framework .


Cada método mencionado (e outro) tem um propósito particular. A principal diferença entre eles é o tipo de Enumeração StringComparison que eles estão usando por padrão. Existem várias opções:

  • CurrentCulture
  • CurrentCultureIgnoreCase
  • InvariantCulture
  • InvariantCultureIgnoreCase
  • Ordinal
  • OrdinalIgnoreCase

Cada um dos tipos de comparação acima segmenta diferentes casos de uso:

  • Ordinal
    • Identificadores internos com distinção entre maiúsculas e minúsculas
    • Identificadores de maiúsculas e minúsculas em padrões como XML e HTTP
    • Configurações relacionadas à segurança que diferenciam maiúsculas de minúsculas
  • OrdinalIgnoreCase
    • Identificadores internos sem distinção entre maiúsculas e minúsculas
    • Identificadores sem distinção entre maiúsculas e minúsculas em padrões como XML e HTTP
    • Caminhos de arquivo (no Microsoft Windows)
    • Chaves / valores do registro
    • Variáveis ​​ambientais
    • Identificadores de resources (nomes de identificador, por exemplo)
    • Configurações relacionadas à segurança insensível a maiúsculas e minúsculas
  • InvariantCulture ou InvariantCultureIgnoreCase
    • Alguns persistiram dados relevantes linguisticamente
    • Exibição de dados lingüísticos que exigem uma ordem de sorting fixa
  • CurrentCulture ou CurrentCultureIgnoreCase
    • Dados exibidos para o usuário
    • A maioria das inputs do usuário

Note que a Enumeração StringComparison , bem como as sobrecargas para methods de comparação de strings, existe desde o .NET 2.0.


String.CompareTo Method (String)

É, na verdade, uma implementação segura do método IComparable.CompareTo . Interpretação padrão: CurrentCulture.

Uso:

O método CompareTo foi projetado principalmente para uso em operações de sorting ou alfabetização

portanto

A implementação da interface IComparable usará necessariamente esse método

Método String.Compare

Um membro estático da class String que possui muitas sobrecargas. Interpretação padrão: CurrentCulture.

Sempre que possível, você deve chamar uma sobrecarga do método Compare que inclui um parâmetro StringComparison.

Método String.Equals

Substituído da class Object e sobrecarregado para segurança de tipo. Interpretação padrão: Ordinal. Notar que:

Os methods de igualdade da class String incluem o Equals estático , o operador static == e o método da instância Equals .


Classe StringComparer

Há também uma outra maneira de lidar com comparações de strings especialmente para classificar:

Você pode usar a class StringComparer para criar uma comparação específica de tipo para classificar os elementos em uma coleção genérica. Classes como Hashtable, Dictionary, SortedList e SortedList usam a class StringComparer para fins de sorting.

Não que o desempenho geralmente importe com 99% das vezes que você precisa fazer isso, mas se você tivesse que fazer isso em um loop vários milhões de vezes eu sugiro que você use .Equals ou == porque assim que encontrar um caractere O que não combina com isso joga tudo como falso, mas se você usar o CompareTo, ele terá que descobrir qual caractere é menor do que o outro, levando a um desempenho um pouco pior.

Se seu aplicativo estiver sendo executado em diferentes países, recomendamos que você dê uma olhada nas implicações do CultureInfo e, possivelmente, use .Equals. Como eu realmente só escrevo aplicativos para os EUA (e não me importo se não funciona corretamente por alguém), eu sempre uso apenas ==.

Nos formulários que você listou aqui, não há muita diferença entre os dois. CompareTo acaba chamando um método CompareInfo que faz uma comparação usando a cultura atual; Equals é chamado pelo operador == .

Se você considera sobrecargas, as coisas ficam diferentes. Compare e == só pode usar a cultura atual para comparar uma string. Equals e String.Compare podem receber um argumento de enumeração StringComparison que permite especificar comparações sem diferenciação de cultura ou sem distinção entre maiúsculas e minúsculas. Apenas String.Compare permite que você especifique um CultureInfo e realize comparações usando uma cultura diferente da cultura padrão.

Devido à sua versatilidade, acho que uso String.Compare mais do que qualquer outro método de comparação; isso me permite especificar exatamente o que eu quero.

Uma grande diferença a notar é que o .Equals () lançará uma exceção se a primeira string for nula, enquanto que == não será.

  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.CompareTo (s2): NÃO use se a finalidade principal é determinar se duas cadeias são equivalentes
  • s1 == s2: não pode ignorar o caso
  • s1.Equals (s2, StringComparison): Lança NullReferenceException se s1 for nulo
  • String.Equals (s2, StringComparison): Por processo de eliminação, este método estático é o WINNER (assumindo um caso de uso típico para determinar se duas strings são equivalentes)!

Usar o .Equals também é muito mais fácil de ler .

com .Equals, você também ganha as opções StringComparison. muito útil para ignorar caso e outras coisas.

btw, isso vai avaliar a falsa

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

Como = = compara os valores de a e b (que são pointers), isso só será avaliado como verdadeiro se os pointers apontarem para o mesmo object na memory. .Equals desreferencia os pointers e compara os valores armazenados nos pointers. a.Equals (b) seria verdade aqui.

e se você mudar b para:

 b = "MYSTRING"; 

então a.Equals (b) é falsa, mas

 a.Equals(b, StringComparison.OrdinalIgnoreCase) 

seria verdade

a.CompareTo (b) chama a function CompareTo da string que compara os valores nos pointers e retorna <0 se o valor armazenado em a for menor que o valor armazenado em b, retorna 0 se a.Equals (b) for true e > 0 caso contrário. No entanto, isso faz distinção entre maiúsculas e minúsculas, acho que há possivelmente opções para CompareTo ignorar maiúsculas e minúsculas, mas não tem tempo para procurar agora. Como outros já afirmaram, isso seria feito para sorting. Comparar a igualdade dessa maneira resultaria em sobrecarga desnecessária.

Tenho certeza de que estou deixando as coisas de fora, mas acho que isso deve ser informação suficiente para começar a experimentar se você precisar de mais detalhes.