Как вам кажется, вы знаете, что нижний регистр двух строк и их сравнение - это не то же самое, что сравнение без учета регистра. На то есть масса причин. Например, стандарт Unicode позволяет кодировать текст с диакритическими знаками несколькими способами. Некоторые символы включают в себя как основной символ, так и диакритический знак в одной кодовой точке. Эти символы также могут быть представлены как основной символ, за которым следует комбинированный диакритический знак. Эти два представления одинаковы для всех целей, и сравнение строк с учетом языка и региональных параметров в .NET Framework правильно идентифицирует их как равные либо с CurrentCulture, либо с InvariantCulture (с IgnoreCase или без него). С другой стороны, порядковое сравнение неправильно расценивает их как неравные.
К сожалению, switch
ничего не делает, кроме порядкового сравнения. Порядковое сравнение подходит для определенных типов приложений, например для анализа файла ASCII с жестко заданными кодами, но сравнение порядковых строк неверно для большинства других целей.
То, что я делал в прошлом, чтобы добиться правильного поведения, - это просто смоделировать свой собственный оператор switch. Есть много способов сделать это. Один из способов - создать List<T>
пару строк case и делегатов. В списке можно искать, используя правильное сравнение строк. Когда совпадение найдено, может быть вызван связанный делегат.
Другой вариант - сделать очевидную цепочку if
утверждений. Обычно это оказывается не так плохо, как кажется, поскольку структура очень правильная.
Самое замечательное в этом то, что на самом деле нет никакого снижения производительности при моделировании вашей собственной функциональности переключателя при сравнении со строками. Система не собирается создавать таблицу переходов O (1) так, как она может с целыми числами, поэтому она все равно будет сравнивать каждую строку по одному.
Если есть много случаев для сравнения и производительность является проблемой, то List<T>
описанный выше параметр можно заменить отсортированным словарем или хеш-таблицей. Тогда производительность может потенциально соответствовать или превышать параметр оператора switch.
Вот пример списка делегатов:
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();
}
Конечно, вы, вероятно, захотите добавить некоторые стандартные параметры и, возможно, тип возвращаемого значения в делегат CustomSwitchDestination. И вам захочется придумать лучшие имена!
Если поведение каждого из ваших случаев не позволяет делегировать вызов таким образом, например, если необходимы разные параметры, то вы застряли в цепочке if
статов. Я тоже делал это несколько раз.
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()
илиToLowerInvariant()
? Кроме того, он не сравнивает две неизвестные строки , он сравнивает одну неизвестную строку с одной известной строкой. Таким образом, пока он знает, как жестко закодировать подходящее представление в верхнем или нижнем регистре, блок переключателя должен работать нормально.