Come sembra che tu sappia, mettere in minuscolo due stringhe e confrontarle non è la stessa cosa che fare un confronto tra maiuscole e minuscole. Ci sono molte ragioni per questo. Ad esempio, lo standard Unicode consente di codificare il testo con segni diacritici in più modi. Alcuni caratteri includono sia il carattere di base che il segno diacritico in un unico punto di codice. Questi caratteri possono anche essere rappresentati come il carattere di base seguito da un carattere diacritico combinato. Queste due rappresentazioni sono uguali a tutti gli effetti e i confronti di stringhe con riconoscimento delle impostazioni cultura in .NET Framework le identificheranno correttamente come uguali, con CurrentCulture o InvariantCulture (con o senza IgnoreCase). Un confronto ordinale, d'altra parte, li considererà erroneamente disuguali.
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 definiti in modo rigido, ma il confronto di stringhe ordinali è sbagliato per la maggior parte degli altri usi.
Quello che ho fatto in passato per ottenere il comportamento corretto è solo una simulazione della mia dichiarazione di switch. Ci sono molti modi per farlo. Un modo sarebbe creare una List<T>
coppia di stringhe case e delegati. L'elenco può essere ricercato utilizzando il confronto di stringhe appropriato. Quando viene trovata la corrispondenza, è possibile richiamare il delegato associato.
Un'altra opzione è fare l'ovvia catena di if
affermazioni. Questo di solito risulta non essere così grave come sembra, poiché la struttura è molto regolare.
La cosa grandiosa di questo è che non c'è davvero alcuna penalità nelle prestazioni nel deridere la propria funzionalità switch quando si confronta con le stringhe. Il sistema non creerà una tabella di salto O (1) come può con i numeri interi, quindi confronterà comunque ogni stringa una alla volta.
Se ci sono molti casi da confrontare e le prestazioni sono un problema, l' List<T>
opzione descritta sopra potrebbe essere sostituita con un dizionario ordinato o una tabella hash. Quindi le prestazioni possono potenzialmente corrispondere o superare l'opzione dell'istruzione switch.
Ecco un esempio dell'elenco 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();
}
Ovviamente, probabilmente vorrai aggiungere alcuni parametri standard e possibilmente un tipo restituito al delegato CustomSwitchDestination. E vorrai fare nomi migliori!
Se il comportamento di ciascuno dei tuoi casi non è suscettibile di delegare l'invocazione in questo modo, ad esempio se sono necessari parametri diversi, allora sei bloccato con if
dichiarazioni concatenate . L'ho fatto anche alcune 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";
}
ToUpperInvariant()
oToLowerInvariant()
? Inoltre, non sta confrontando due stringhe sconosciute , sta confrontando una stringa sconosciuta con una stringa nota. Pertanto, fintanto che sa come codificare la rappresentazione appropriata in maiuscolo o minuscolo, il blocco interruttore dovrebbe funzionare bene.