Pergunta

Comparar strings em C# é bastante simples.Na verdade, existem várias maneiras de fazer isso.Listei alguns no bloco abaixo.O que me interessa são as diferenças entre eles e quando um deve ser usado em vez dos outros?Deve-se evitar a todo custo?Há mais que não listei?

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

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

(Observação:Estou procurando igualdade neste exemplo, nem menor nem maior, mas sinta-se à vontade para comentar sobre isso também)

Foi útil?

Solução

Aqui estão as regras de como essas funções funcionam:

stringValue.CompareTo(otherStringValue)

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

stringValue.Equals(otherStringValue)

  1. null não é considerado igual a nada
  2. a menos que você especifique um StringComparison opção, ele usará o que parece ser uma verificação direta de igualdade ordinal, 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 a estática Equals(string a, string b) método (que por sua vez vai para um método interno EqualsHelper para fazer a comparação.
  3. Chamando .Equals() com um null string obtém null exceção de referência, enquanto em == não.

Object.ReferenceEquals(stringValue, otherStringValue)

Apenas verifica se as referências são iguais, ou seja,não são apenas duas strings com o mesmo conteúdo, você está comparando um objeto string consigo 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ê quiser 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.

Outras dicas

Do MSDN:

"O método compareto foi projetado principalmente para uso em operações de classificação ou alfabetização.Não deve ser usado quando o objetivo principal da chamada do método é determinar se duas seqüências são equivalentes.Para determinar se duas cordas são equivalentes, chame o método igual. "

Eles sugerem usar .Equals em vez de .CompareTo quando procuramos apenas a igualdade.Não tenho certeza se há uma diferença entre .Equals e == para o string aula.às vezes vou usar .Equals ou Object.ReferenceEquals em vez de == para minhas próprias aulas, caso alguém apareça mais tarde e redefina o == operador para essa classe.

Se você estiver curioso sobre as diferenças nos métodos BCL, Refletor é seu amigo :-)

Eu sigo estas diretrizes:

Combinação exata: EDITAR:Anteriormente, eu sempre usei o operador == com base no princípio de que dentro de Equals(string, string) o operador object == é usado para comparar as referências do objeto, mas parece que strA.Equals(strB) ainda é 1-11% mais rápido do que string. Igual a (strA, strB), strA == strB e string.CompareOrdinal (strA, strB).Fiz um loop testado com um StopWatch em valores de string internados/não internados, com comprimentos de string iguais/diferentes e tamanhos variados (1B a 5MB).

strA.Equals(strB)

Correspondência legível por humanos (culturas ocidentais, sem distinção entre maiúsculas e minúsculas):

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

Correspondência legível por humanos (todas as outras culturas, maiúsculas e minúsculas/acento/kana/etc definidas por 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. dito, CompareTo é usado para classificação.

Há uma diferença, entretanto, 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 simples razão é que o seguinte gerará uma exceção:

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

bool equal = a.Equals(b);

E o seguinte não:

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

bool equal = a == b;

Boas explicações e práticas sobre problemas de comparação de strings podem ser encontradas no artigo Novas recomendações para uso de strings no Microsoft .NET 2.0 e também em Melhores práticas para usar strings no .NET Framework.


Cada um dos métodos mencionados (e outros) tem um propósito específico.A principal diferença entre eles é que tipo de Enumeração StringComparison eles estão usando por padrão.Existem várias opções:

  • Cultura Atual
  • Cultura AtualIgnoreCase
  • Cultura Invariável
  • InvariantCultureIgnoreCase
  • Ordinal
  • OrdinalIgnoreCase

Cada um dos tipos de comparação acima tem como alvo diferentes casos de uso:

  • Ordinal
    • Identificadores internos que diferenciam maiúsculas de minúsculas
    • Identificadores que diferenciam maiúsculas de minúsculas em padrões como XML e HTTP
    • Configurações relacionadas à segurança que diferenciam maiúsculas de minúsculas
  • OrdinalIgnoreCase
    • Identificadores internos que não diferenciam maiúsculas de minúsculas
    • Identificadores que não diferenciam maiúsculas de minúsculas em padrões como XML e HTTP
    • Caminhos de arquivo (no Microsoft Windows)
    • Chaves/valores de registro
    • Variáveis ​​ambientais
    • Identificadores de recursos (nomes de identificador, por exemplo)
    • Configurações relacionadas à segurança que não diferenciam maiúsculas de minúsculas
  • InvariantCulture ou InvariantCultureIgnoreCase
    • Alguns dados linguísticamente relevantes persistiram
    • Exibição de dados linguísticos que exigem uma ordem de classificação fixa
  • CurrentCulture ou CurrentCultureIgnoreCase
    • Dados exibidos ao usuário
    • A maioria das entradas do usuário

Observe que Enumeração StringComparison bem como sobrecargas para métodos de comparação de strings, existem desde o .NET 2.0.


Método String.CompareTo (String)

É de fato uma implementação segura do tipo Método IComparable.CompareTo.Interpretação padrão:Cultura Atual.

Uso:

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

Por isso

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

Método String.Compare

Um membro estático de Classe de cordas que tem muitas sobrecargas.Interpretação padrão:Cultura Atual.

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 classe Object e sobrecarregado para segurança de tipo.Interpretação padrão:Ordinal.Notar que:

Os métodos de igualdade da classe String incluem o estáticos iguais, o operador estático ==, e a método de instância igual a.


Classe StringComparer

Há também outra maneira de lidar com comparações de strings, especialmente voltadas para classificação:

Você pode usar o Classe 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 classe StringComparer para fins de classificação.

Não que o desempenho geralmente importe 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 isso não corresponde, tudo será considerado falso, mas se você usar o CompareTo, ele terá que descobrir qual caractere é menor que o outro, levando a um tempo de desempenho um pouco pior.

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

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

Se você considerar as sobrecargas, as coisas ficam diferentes. Compare e == só pode usar a cultura atual para comparar uma string. Equals e String.Compare pode levar um StringComparison argumento de enumeração que permite especificar comparações que não diferenciam cultura ou maiúsculas de minúsculas.Apenas String.Compare permite que você especifique um CultureInfo e realizar 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;permite-me especificar exatamente o que quero.

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

       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 o objetivo principal for determinar se duas strings são equivalentes
  • s1 == s2: Não é possível ignorar maiúsculas e minúsculas
  • s1.Equals(s2, Comparação de String): Lança NullReferenceException se s1 for nulo
  • String.Equals(s2, StringComparison): Por processo de eliminação, este estático método é o GANHADOR (assumindo um caso de uso típico para determinar se duas strings são equivalentes)!

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

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

aliás, isso será avaliado como falso

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

return a==b

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

e se você mudar b para:

b = "MYSTRING";

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

a.Equals(b, StringComparison.OrdinalIgnoreCase) 

seria verdade

a.CompareTo(b) chama a função CompareTo da string que compara os valores nos ponteiros e retorna <0 se o valor armazenado em a for menor que o valor armazenado em b, retorna 0 se a.Equals(b) for verdadeiro e >0 caso contrário.No entanto, isso diferencia maiúsculas de minúsculas, acho que possivelmente existem opções para CompareTo ignorar maiúsculas e minúsculas, mas não tenho tempo para olhar agora.Como outros já afirmaram, isso seria feito para classificação.Comparar a igualdade dessa maneira resultaria em sobrecarga desnecessária.

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top