Если у меня есть оператор case оператора switch, где объект в переключателе является строкой, действительно ли возможно сделать так или иначе ignoreCase, выдерживают сравнение?
Я имею, например:
string s = "house";
switch (s)
{
case "houSe": s = "window";
}
Будет s получать значение "окно". Как переопределить оператора case оператора switch, таким образом, он сравнит строки с помощью ignoreCase?
Как вы, кажется, знаете, уменьшение двух строк в нижнем регистре и их сравнение - это не то же самое, что сравнение без учета регистра. Для этого есть масса причин. Например, стандарт Unicode позволяет кодировать текст с диакритическими знаками несколькими способами. Некоторые символы включают в себя как базовый символ, так и диакритический знак в одной кодовой точке. Эти символы также могут быть представлены как основной символ, за которым следует комбинированный диакритический знак. Эти два представления одинаковы для всех целей, и сравнение строк с учетом языка и региональных параметров в .NET Framework правильно идентифицирует их как равные либо с CurrentCulture, либо с InvariantCulture (с IgnoreCase или без него). С другой стороны, порядковое сравнение неправильно расценивает их как неравные.
К сожалению, переключатель
не выполняет ничего, кроме порядкового сравнения. Порядковое сравнение подходит для определенных типов приложений, например для анализа файла ASCII с жестко заданными кодами, но сравнение порядковых строк неверно для большинства других целей.
То, что я делал в прошлом, чтобы добиться правильного поведения, - это просто макет моего собственного оператора switch. Есть много способов сделать это.Один из способов - создать List
пар строк case и делегатов. В списке можно искать, используя правильное сравнение строк. Когда совпадение найдено, может быть вызван связанный делегат.
Другой вариант - выполнить очевидную цепочку операторов if
. Обычно это оказывается не так плохо, как кажется, поскольку структура очень правильная.
Самое замечательное в этом то, что на самом деле нет никакого снижения производительности при моделировании вашей собственной функциональности переключателя при сравнении со строками. Система не собирается создавать таблицу переходов O (1) так, как она может с целыми числами, поэтому она в любом случае будет сравнивать каждую строку по одному.
Если есть много случаев для сравнения и производительность является проблемой, то параметр List
, описанный выше, может быть заменен отсортированным словарем или хеш-таблицей. Тогда производительность может потенциально соответствовать параметру оператора 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";
}
Более простой подход - это просто уменьшить регистр строки до того, как она войдет в оператор switch, и сделать регистр более низким.
На самом деле, верхняя граница немного лучше с чисто экстремальной наносекундной точки зрения производительности, но менее естественна на вид.
Например:
string s = "house";
switch (s.ToLower()) {
case "house":
s = "window";
break;
}