Differenze nei metodi di confronto delle stringhe in C#
-
09-06-2019 - |
Domanda
Confrontare le stringhe in C# è piuttosto semplice.In effetti ci sono diversi modi per farlo.Ne ho elencati alcuni nel blocco sottostante.Ciò che mi incuriosisce sono le differenze tra loro e quando uno dovrebbe essere usato rispetto agli altri?Uno dovrebbe essere evitato a tutti i costi?Ce ne sono altri che non ho elencato?
string testString = "Test";
string anotherString = "Another";
if (testString.CompareTo(anotherString) == 0) {}
if (testString.Equals(anotherString)) {}
if (testString == anotherString) {}
(Nota:Sto cercando l'uguaglianza in questo esempio, non inferiore o superiore a, ma sentiti libero di commentare anche questo)
Soluzione
Ecco le regole su come funzionano queste funzioni:
stringValue.CompareTo(otherStringValue)
null
viene prima di una stringa- utilizza
CultureInfo.CurrentCulture.CompareInfo.Compare
, il che significa che utilizzerà un confronto dipendente dalle impostazioni cultura.Questo potrebbe significare questoß
confronterà uguale aSS
in Germania o simili
stringValue.Equals(otherStringValue)
null
non è considerato uguale a nulla- a meno che non specifichi a
StringComparison
opzione, utilizzerà quello che sembra un controllo di uguaglianza ordinale diretto, vale a direß
non è lo stesso diSS
, in qualsiasi lingua o cultura
stringValue == otherStringValue
- Non è la stessa cosa di
stringValue.Equals()
. - IL
==
l'operatore chiama l'operatore staticoEquals(string a, string b)
metodo (che a sua volta va a un metodo internalEqualsHelper
per fare il confronto. - Chiamando
.Equals()
su anull
la stringa ottienenull
eccezione di riferimento, mentre è attivo==
non.
Object.ReferenceEquals(stringValue, otherStringValue)
Controlla solo che i riferimenti siano gli stessi, ad es.non sono solo due stringhe con lo stesso contenuto, stai confrontando un oggetto stringa con se stesso.
Tieni presente che con le opzioni precedenti che utilizzano chiamate al metodo, sono presenti sovraccarichi con più opzioni per specificare come confrontare.
Il mio consiglio se vuoi solo verificare l'uguaglianza è di decidere se vuoi usare un confronto dipendente dalla cultura o meno, e poi usare .CompareTo
O .Equals
, a seconda della scelta.
Altri suggerimenti
Da MSDN:
"Il metodo comparativo è stato progettato principalmente per l'uso nelle operazioni di smistamento o alfabetizzazione.Non dovrebbe essere usato quando lo scopo principale della chiamata del metodo è determinare se due stringhe sono equivalenti.Per determinare se due stringhe sono equivalenti, chiamare il metodo Equals. "
Suggeriscono di usare .Equals
invece di .CompareTo
quando si cerca esclusivamente l’uguaglianza.Non sono sicuro che ci sia una differenza tra .Equals
E ==
per il string
classe.A volte userò .Equals
O Object.ReferenceEquals
invece di ==
per le mie lezioni nel caso in cui qualcuno arrivi in un secondo momento e ridefinisca il ==
operatore per quella classe.
Se sei mai curioso delle differenze nei metodi BCL, Riflettore È tuo amico :-)
Seguo queste linee guida:
Corrispondenza esatta: MODIFICARE:In precedenza ho sempre utilizzato l'operatore == in base al principio che all'interno di Equals(string, string) l'operatore object == viene utilizzato per confrontare i riferimenti all'oggetto ma sembra che strA.Equals(strB) sia ancora complessivamente più veloce dell'1-11% rispetto a string. Equals(strA, strB), strA == strB e string.CompareOrdinal(strA, strB).Ho testato il loop con un cronometro su valori di stringa interni/non interni, con lunghezze di stringa uguali/diverse e dimensioni variabili (da 1B a 5 MB).
strA.Equals(strB)
Corrispondenza leggibile dall'uomo (culture occidentali, senza distinzione tra maiuscole e minuscole):
string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase) == 0
Corrispondenza leggibile dall'uomo (tutte le altre culture, maiuscole/minuscole/accento/kana/ecc. definiti da CultureInfo):
string.Compare(strA, strB, myCultureInfo) == 0
Corrispondenza leggibile dall'uomo con regole personalizzate (tutte le altre culture):
CompareOptions compareOptions = CompareOptions.IgnoreCase
| CompareOptions.IgnoreWidth
| CompareOptions.IgnoreNonSpace;
string.Compare(strA, strB, CultureInfo.CurrentCulture, compareOptions) == 0
COME Ed detto, CompareTo viene utilizzato per l'ordinamento.
C'è una differenza, tuttavia, tra .Equals e ==.
== risolve a essenzialmente il seguente codice:
if(object.ReferenceEquals(left, null) &&
object.ReferenceEquals(right, null))
return true;
if(object.ReferenceEquals(left, null))
return right.Equals(left);
return left.Equals(right);
Il semplice motivo è che quanto segue genererà un'eccezione:
string a = null;
string b = "foo";
bool equal = a.Equals(b);
E quanto segue non lo farà:
string a = null;
string b = "foo";
bool equal = a == b;
Buone spiegazioni e pratiche sui problemi di confronto delle stringhe possono essere trovate nell'articolo Nuovi consigli per l'utilizzo delle stringhe in Microsoft .NET 2.0 e anche dentro Procedure consigliate per l'uso delle stringhe in .NET Framework.
Ciascuno dei metodi menzionati (e altri) ha uno scopo particolare.La differenza fondamentale tra loro è il tipo di Enumerazione StringComparison stanno utilizzando per impostazione predefinita.Ci sono diverse opzioni:
- Cultura attuale
- CurrentCultureIgnoreCase
- Cultura invariante
- InvariantCultureIgnoreCase
- Ordinale
- OrdinalIgnoreCase
Ciascuno dei tipi di confronto sopra indicati si rivolge a casi d'uso diversi:
- Ordinale
- Identificatori interni con distinzione tra maiuscole e minuscole
- Identificatori con distinzione tra maiuscole e minuscole in standard come XML e HTTP
- Impostazioni relative alla sicurezza con distinzione tra maiuscole e minuscole
- OrdinalIgnoreCase
- Identificatori interni senza distinzione tra maiuscole e minuscole
- Identificatori senza distinzione tra maiuscole e minuscole in standard come XML e HTTP
- Percorsi dei file (su Microsoft Windows)
- Chiavi/valori del registro
- Variabili ambientali
- Identificatori delle risorse (nomi di handle, ad esempio)
- Impostazioni relative alla sicurezza senza distinzione tra maiuscole e minuscole
- InvariantCulture o InvariantCultureIgnoreCase
- Alcuni dati persistentemente rilevanti dal punto di vista linguistico
- Visualizzazione di dati linguistici che richiedono un ordinamento fisso
- CurrentCulture o CurrentCultureIgnoreCase
- Dati visualizzati all'utente
- La maggior parte degli input dell'utente
Notare che Enumerazione StringComparison così come gli sovraccarichi per i metodi di confronto delle stringhe, esistono da .NET 2.0.
Metodo String.CompareTo (String)
È infatti un'implementazione sicura di tipo Metodo IComparable.CompareTo.Interpretazione predefinita:Cultura attuale.
Utilizzo:
Il metodo CompareTo è stato progettato principalmente per l'utilizzo nelle operazioni di ordinamento o alfabetizzazione
Così
L'implementazione dell'interfaccia IComparable utilizzerà necessariamente questo metodo
Metodo String.Compare
Un membro statico di Classe di corde che ha molti sovraccarichi.Interpretazione predefinita:Cultura attuale.
Quando possibile, è necessario chiamare un sovraccarico del metodo Compare che includa un parametro StringComparison.
Metodo String.Equals
Sostituito dalla classe Object e sovraccaricato per l'indipendenza dai tipi.Interpretazione predefinita:Ordinale.Notare che:
I metodi di uguaglianza della classe String includono Uguali statici, IL operatore statico ==, e il metodo di istanza Equals.
Classe StringComparer
Esiste anche un altro modo per gestire i confronti tra stringhe, in particolare mirato all'ordinamento:
Puoi usare il Classe StringComparer per creare un confronto specifico per il tipo per ordinare gli elementi in una raccolta generica.Classi come Hashtable, Dictionary, SortedList e SortedList utilizzano la classe StringComparer per scopi di ordinamento.
Non che le prestazioni di solito siano importanti nel 99% dei casi in cui è necessario farlo, ma se dovessi farlo in un ciclo diversi milioni di volte ti consiglio vivamente di utilizzare .Equals o == perché non appena trova un carattere che non corrisponde, considera tutto falso, ma se usi CompareTo dovrà capire quale carattere è inferiore all'altro, portando a tempi di prestazione leggermente peggiori.
Se la tua app verrà eseguita in paesi diversi, ti consiglio di dare un'occhiata alle implicazioni di CultureInfo ed eventualmente utilizzare .Equals.Dato che in realtà scrivo solo app per gli Stati Uniti (e non mi interessa se non funziona correttamente da qualcuno), utilizzo sempre e semplicemente ==.
Nei moduli che hai elencato qui, non c'è molta differenza tra i due. CompareTo
finisce per chiamare a CompareInfo
metodo che fa un confronto utilizzando la cultura attuale; Equals
è chiamato dal ==
operatore.
Se consideriamo i sovraccarichi, le cose cambiano. Compare
E ==
può utilizzare solo le impostazioni cultura correnti per confrontare una stringa. Equals
E String.Compare
può prendere a StringComparison
argomento di enumerazione che consente di specificare confronti senza distinzione di cultura o senza distinzione tra maiuscole e minuscole.Soltanto String.Compare
consente di specificare a CultureInfo
ed eseguire confronti utilizzando una lingua diversa da quella predefinita.
Per la sua versatilità, trovo che lo utilizzo String.Compare
più di ogni altro metodo di confronto;mi permette di specificare esattamente quello che voglio.
Una GRANDE differenza da notare è che .Equals() genererà un'eccezione se la prima stringa è nulla, mentre == non lo farà.
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.Confronta con(s2): NON utilizzare se lo scopo principale è determinare se due stringhe sono equivalenti
- s1 == s2: Non è possibile ignorare il caso
- s1.Equals(s2, StringComparison): Genera NullReferenceException se s1 è null
- String.Equals(s2, StringComparison): Per processo di eliminazione, questo statico il metodo è il VINCITORE (assumendo un caso d'uso tipico per determinare se due stringhe sono equivalenti)!
Usare .Equals è anche molto più semplice Leggere.
con .Equals, ottieni anche le opzioni StringComparison.molto utile per ignorare maiuscole e minuscole e altre cose.
btw, questo valuterà falso
string a = "myString";
string b = "myString";
return a==b
Poiché == confronta i valori di a e b (che sono puntatori), verrà valutato vero solo se i puntatori puntano allo stesso oggetto in memoria..Equals dereferenzia i puntatori e confronta i valori memorizzati nei puntatori.a.Equals(b) sarebbe vero qui.
e se cambi b in:
b = "MYSTRING";
allora a.Equals(b) è falso, ma
a.Equals(b, StringComparison.OrdinalIgnoreCase)
sarebbe vero
a.CompareTo(b) chiama la funzione CompareTo della stringa che confronta i valori nei puntatori e restituisce <0 se il valore memorizzato in a è inferiore al valore memorizzato in b, restituisce 0 se a.Equals(b) è vero e >0 altrimenti.Tuttavia, questo fa distinzione tra maiuscole e minuscole, penso che ci siano forse opzioni per CompareTo per ignorare maiuscole e minuscole e simili, ma non ho tempo di guardare ora.Come altri hanno già affermato, questo verrebbe fatto per l'ordinamento.Il confronto per l'uguaglianza in questo modo comporterebbe spese generali inutili.
Sono sicuro di tralasciare alcune cose, ma penso che queste informazioni dovrebbero essere sufficienti per iniziare a sperimentare se hai bisogno di maggiori dettagli.