Как вы, кажется, чтобы быть в курсе, lowercasing две строки и сравнивая их не то же самое, как делают в сравнение игнорирований случай. Для этого есть много причин. Например, стандарт Unicode позволяет кодировать текст с диакритикой несколькими способами. Некоторые символы включают в себя как базовый, так и диакритический символы в одной кодовой точке. Эти символы также могут быть представлены в качестве базового символа, сопровождаемого сочетанием диакритического характера. Эти два представления равны для всех целей, а сопоставления строк, поддерживающие культуру в .NET Framework, будут правильно идентифицировать их как равные, либо с CurrentCulture, либо с InvariantCulture (с или без IgnoreCase). С другой стороны, порядковое сравнение будет неправильно рассматривать их как неравные.
К сожалению, switch
не делает ничего, кроме порядкового сравнения. Очередное сравнение отлично подходит для некоторых видов приложений, таких как синтаксический анализ файла ASCII с жестко определенными кодами, но сравнение обычных строк не подходит для большинства других целей.
То, что я делал в прошлом, чтобы получить правильное поведение, - это просто макет моего собственного оператора switch. Есть много способов сделать это. Один из способов - создать List<T>
пар строк и делегатов. Список можно искать, используя правильное сравнение строк. Когда совпадение найдено, может быть вызван связанный делегат.
Другой вариант - сделать очевидную цепочку операторов 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()'? Кроме того, он не сравнивает две неизвестные строки, он сравнивает одну неизвестную строку с одной известной строкой. Таким образом, до тех пор, пока он знает, как жестко кодировать подходящее представление верхнего или нижнего регистра, блок коммутатора должен работать нормально. –
@Seth Petry-Johnson - Возможно, эта оптимизация может быть выполнена, но причина, по которой параметры сравнения строк испекиваются в рамках структуры, заключается в том, что мы не все должны становиться специалистами по лингвистике для написания правильного расширяемого программного обеспечения. –
OK. Я приведу пример, где это будет доступно. Предположим, что вместо «дома» у нас было (английское!) Слово «café». Это значение может быть представлено одинаково хорошо (и в равной степени) с помощью «caf \ u00E9» или «cafe \ u0301». Ординальное равенство (как в инструкции switch) с 'ToLower()' или 'ToLowerInvariant()' будет возвращать false. 'Equals' с' StringComparison.InvariantCultureIgnoreCase' вернет true. Поскольку обе последовательности выглядят одинаково при отображении, версия 'ToLower()' является неприятной ошибкой для отслеживания. Вот почему всегда лучше делать правильные сравнения строк, даже если вы не турецкий. –