Как заставить Оператор переключения C# использовать IgnoreCase

Если у меня есть оператор case оператора switch, где объект в переключателе является строкой, действительно ли возможно сделать так или иначе ignoreCase, выдерживают сравнение?

Я имею, например:

string s = "house";
switch (s)
{
  case "houSe": s = "window";
}

Будет s получать значение "окно". Как переопределить оператора case оператора switch, таким образом, он сравнит строки с помощью ignoreCase?

72
задан John Saunders 25 February 2010 в 13:37
поделиться

2 ответа

Как вы, кажется, знаете, уменьшение двух строк в нижнем регистре и их сравнение - это не то же самое, что сравнение без учета регистра. Для этого есть масса причин. Например, стандарт 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";
    }
57
ответ дан 24 November 2019 в 12:27
поделиться

Более простой подход - это просто уменьшить регистр строки до того, как она войдет в оператор switch, и сделать регистр более низким.

На самом деле, верхняя граница немного лучше с чисто экстремальной наносекундной точки зрения производительности, но менее естественна на вид.

Например:

string s = "house"; 
switch (s.ToLower()) { 
  case "house": 
    s = "window"; 
    break;
}
72
ответ дан 24 November 2019 в 12:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: