Come ti sembra di essere a conoscenza, caratteri minuscoli due stringhe e confrontandoli non è lo stesso di fare un confronto ignorare e minuscole. Ci sono molte ragioni per questo. Ad esempio, lo standard Unicode consente al testo con segni diacritici di essere codificato in più modi. Alcuni caratteri includono sia il carattere di base che il segno diacritico in un singolo punto di codice. Questi personaggi possono anche essere rappresentati come il personaggio base seguito da un carattere diacritico che combina. Queste due rappresentazioni sono uguali per tutti gli scopi, e i confronti delle stringhe compatibili con la cultura in .NET Framework li identificheranno correttamente come uguali, con CurrentCulture o InvariantCulture (con o senza IgnoreCase). Un confronto ordinale, d'altro canto, li considererà erroneamente ineguali.
Sfortunatamente, switch
non fa altro che un confronto ordinale. Un confronto ordinale va bene per alcuni tipi di applicazioni, come l'analisi di un file ASCII con codici rigidamente definiti, ma il confronto tra stringhe ordinali è sbagliato per la maggior parte degli altri usi.
Quello che ho fatto in passato per ottenere il comportamento corretto è solo prendere in giro la mia dichiarazione di switch. Ci sono molti modi per farlo. Un modo sarebbe creare uno List<T>
di coppie di stringhe e delegati. L'elenco può essere cercato utilizzando il confronto di stringhe corretto. Quando viene trovata la corrispondenza, è possibile richiamare il delegato associato.
Un'altra opzione è fare l'ovvia catena di istruzioni if
. Questo di solito risulta non essere così male come sembra, dato che la struttura è molto regolare.
La cosa grandiosa di questo è che non ci sono realmente penalità di prestazioni nel prendere in giro la propria funzionalità di switch quando si confrontano le stringhe. Il sistema non ha intenzione di creare una tabella di salto O (1) nel modo in cui può farlo con gli interi, quindi dovrà comunque confrontare ogni stringa una alla volta.
Se esistono molti casi da confrontare e le prestazioni rappresentano un problema, l'opzione List<T>
descritta in precedenza potrebbe essere sostituita con un dizionario ordinato o una tabella hash. Quindi la prestazione potrebbe potenzialmente corrispondere o superare l'opzione di istruzione switch.
Ecco un esempio della lista dei delegati:
delegate void CustomSwitchDestination();
List<KeyValuePair<string, CustomSwitchDestination>> customSwitchList;
CustomSwitchDestination defaultSwitchDestination = new CustomSwitchDestination(NoMatchFound);
void CustomSwitch(string value)
{
foreach (var switchOption in customSwitchList)
if (switchOption.Key.Equals(value, StringComparison.InvariantCultureIgnoreCase))
{
switchOption.Value.Invoke();
return;
}
defaultSwitchDestination.Invoke();
}
Certo, probabilmente si vorrà aggiungere alcuni parametri standard e, eventualmente, un tipo di ritorno al delegato CustomSwitchDestination. E vorresti fare nomi migliori!
Se il comportamento di ciascuno dei casi non è suscettibile di delegare il richiamo in questo modo, ad esempio se sono necessari parametri diversi, allora si è bloccati con le dichiarazioni concatenate if
. L'ho fatto anche un paio di volte.
if (s.Equals("house", StringComparison.InvariantCultureIgnoreCase))
{
s = "window";
}
else if (s.Equals("business", StringComparison.InvariantCultureIgnoreCase))
{
s = "really big window";
}
else if (s.Equals("school", StringComparison.InvariantCultureIgnoreCase))
{
s = "broken window";
}
A meno che non mi sbagli, i due sono diversi solo per alcune culture (come il turco), e in tal caso non potrebbe usare 'ToUpperInvariant()' o 'ToLowerInvariant()'? Inoltre, non sta confrontando _due stringhe sconosciute_, sta confrontando una stringa sconosciuta con una stringa nota. Quindi, purché sappia come hardcodificare la rappresentazione superiore o minuscola adatta, il blocco interruttore dovrebbe funzionare correttamente. –
@Seth Petry-Johnson - Forse l'ottimizzazione potrebbe essere apportata, ma il motivo per cui le opzioni di comparazione delle stringhe sono inserite nel framework è che non tutti devono diventare esperti di linguistica per scrivere software corretto ed estensibile. –
OK. Darò un esempio in cui è pertinente. Supponiamo che al posto di "casa" avessimo la parola "café" (inglese!). Questo valore potrebbe essere rappresentato ugualmente bene (e ugualmente probabile) da "caf \ u00E9" o "cafe \ u0301". L'uguaglianza ordinale (come in un'istruzione switch) con 'ToLower()' o 'ToLowerInvariant()' restituirà false. 'Equals' con' StringComparison.InvariantCultureIgnoreCase' restituirà true. Poiché entrambe le sequenze appaiono identiche quando visualizzate, la versione 'ToLower()' è un bug sgradevole da rintracciare. Questo è il motivo per cui è sempre meglio fare confronti con le stringhe corrette, anche se non sei turco. –