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

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

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

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

Получит значение «окно». Как переопределить оператор switch-case, чтобы он сравнивал строки с помощью ignoreCase?

Как вам, кажется, известно, что нижняя шкала двух строк и их сравнение не то же самое, что и сравнение с игнорированием. Для этого есть много причин. Например, стандарт Unicode позволяет кодировать текст с диакритикой несколькими способами. Некоторые символы include в себя как базовый, так и диакритический символы в одной кодовой точке. Эти символы также могут быть представлены в качестве базового символа, сопровождаемого сочетанием диакритического характера. Эти два представления равны для всех целей, а сопоставления строк, поддерживающие культуру в .NET Framework, будут правильно идентифицировать их как равные, либо с CurrentCulture, либо с InvariantCulture (с или без IgnoreCase). С другой стороны, порядковое сравнение будет неправильно рассматривать их как неравные.

К сожалению, switch не делает ничего, кроме сравнительного сравнения. Очередное сравнение отлично подходит для некоторых видов приложений, таких как синтаксический анализ файла ASCII с жестко определенными кодами, но сравнение обычных строк не подходит для большинства других целей.

То, что я делал в прошлом, чтобы получить правильное поведение, – это просто макет моего собственного оператора switch. Есть много способов сделать это. Один из способов – создать List пар строк и делегатов case. Список можно искать, используя правильное сравнение строк. Когда совпадение найдено, может быть вызван связанный делегат.

Другой вариант – сделать очевидную цепочку операторов if . Это, как правило, не так плохо, как кажется, так как структура очень правильная.

Самое замечательное в этом заключается в том, что на самом деле нет никакого штрафа за производительность при издевательстве вашей собственной функциональности коммутатора при сравнении с строками. Система не собирается делать таблицу перехода O (1) так, как она может быть с целыми числами, поэтому она будет сравнивать каждую строку по одному в любом случае.

Если есть много случаев для сравнения, а производительность – проблема, то описанная выше опция List может быть заменена отсортированным словарем или хеш-таблицей. Тогда производительность может потенциально соответствовать или превышать параметр оператора switch.

Ниже приведен пример списка делегатов:

 delegate void CustomSwitchDestination(); List> 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. И вы хотите сделать лучшие имена!

Если поведение каждого из ваших случаев не подлежит делегированию вызова таким образом, например, если параметры differnt необходимы, то вы застряли с прикованными в 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; } 

В некоторых случаях может быть хорошей идеей использовать перечисление. Итак, сначала проанализируйте перечисление (с флагом ignoreCase true), а затем включите перечислитель.

 SampleEnum Result; bool Success = SampleEnum.TryParse(inputText, true, out Result); if(!Success){ //value was not in the enum values }else{ switch (Result) { case SampleEnum.Value1: break; case SampleEnum.Value2: break; default: //do default behaviour break; } } 

Извините за это новое сообщение по старому вопросу, но есть новая опция для решения этой проблемы с использованием C # 7 (VS 2017).

C # 7 теперь предлагает «сопоставление шаблонов», и его можно использовать для решения этой проблемы:

 string houseName = "house"; // value to be tested, ignoring case string windowName; // switch block will set value here switch (true) { case bool b when houseName.Equals("MyHouse", StringComparison.InvariantCultureIgnoreCase): windowName = "MyWindow"; break; case bool b when houseName.Equals("YourHouse", StringComparison.InvariantCultureIgnoreCase): windowName = "YourWindow"; break; case bool b when houseName.Equals("House", StringComparison.InvariantCultureIgnoreCase): windowName = "Window"; break; default: windowName = null; break; } 

В этом решении также рассматривается проблема, упомянутая в ответе @Jeffrey L Whitledge, что сравнение строк без учета регистра не совпадает с сравнением двух строчек с нижним обсазом.

Кстати, в феврале 2017 года в журнале Visual Studio Magazine появилась интересная статья, описывающая сопоставление образцов и способы ее использования в блоках case. Посмотрите: сопоставление образцов в C # 7.0 Case Blocks

РЕДАКТИРОВАТЬ

В свете ответа @ LewisM важно отметить, что оператор switch имеет новое, интересное поведение. То есть, если ваш оператор case содержит объявление переменной, то значение, указанное в части switch копируется в переменную, объявленную в этом case . В следующем примере значение true копируется в локальную переменную b . Кроме того, переменная b не используется и существует только для того, чтобы предложение when в case могло существовать:

 switch(true) { case bool b when houseName.Equals("X", StringComparison.InvariantCultureIgnoreCase): windowName = "X-Window";): break; } 

Как указывает @LewisM, это можно использовать для выгоды – это преимущество в том, что сравниваемая вещь на самом деле находится в инструкции switch , как это происходит с classическим использованием оператора switch . Кроме того, временные значения, объявленные в заявлении case могут предотвратить нежелательные или непреднамеренные изменения исходного значения:

 switch(houseName) { case string hn when hn.Equals("X", StringComparison.InvariantCultureIgnoreCase): windowName = "X-Window"; break; } 

Одним из возможных способов было бы использование словаря с игнорированием словаря с делегатом действия.

 string s = null; var dic = new Dictionary(StringComparer.CurrentCultureIgnoreCase) { {"house", () => s = "window"}, {"house2", () => s = "window2"} }; dic["HouSe"](); 

Расширение ответа на @STLDeveloperA. Новый способ сделать оценку утверждения без нескольких операторов if с c # 7 использует инструкцию соответствия шаблону, аналогичную способу @STLDeveloper, хотя этот способ включает переменную, которая переключается

 string houseName = "house"; // value to be tested string s; switch (houseName) { case var name when name.Equals("Bungalow", StringComparison.InvariantCultureIgnoreCase): s = "Single glazed"; break; case var name when name.Equals("Church", StringComparison.InvariantCultureIgnoreCase); s = "Stained glass"; break; ... default: s = "No windows (cold or dark)" break; } 

В журнале с визуальной студией есть хорошая статья о шаблонных блоках, которые могут стоить взгляда.

Я надеюсь, что это поможет попытаться преобразовать всю строку в конкретный случай либо в нижний регистр, либо в верхний регистр и использовать строчную строку для сравнения:

 public string ConvertMeasurements(string unitType, string value) { switch (unitType.ToLower()) { case "mmol/l": return (Double.Parse(value) * 0.0555).ToString(); case "mg/dl": return (double.Parse(value) * 18.0182).ToString(); } } 

Вот решение, которое обертывает решение @Magnus в classе:

 public class SwitchCaseIndependent : IEnumerable> { private readonly Dictionary _cases = new Dictionary(StringComparer.OrdinalIgnoreCase); public void Add(string theCase, Action theResult) { _cases.Add(theCase, theResult); } public Action this[string whichCase] { get { if (!_cases.ContainsKey(whichCase)) { throw new ArgumentException($"Error in SwitchCaseIndependent, \"{whichCase}\" is not a valid option"); } //otherwise return _cases[whichCase]; } } public IEnumerator> GetEnumerator() { return _cases.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _cases.GetEnumerator(); } } 

Вот пример использования его в простом приложении Windows Form:

  var mySwitch = new SwitchCaseIndependent { {"hello", () => MessageBox.Show("hello")}, {"Goodbye", () => MessageBox.Show("Goodbye")}, {"SoLong", () => MessageBox.Show("SoLong")}, }; mySwitch["HELLO"](); 

Если вы используете lambdas (например, пример), вы получаете замыкания, которые будут захватывать ваши локальные переменные (довольно близкие к ощущениям, которые вы получаете от оператора switch).

Поскольку он использует словарь под обложками, он получает поведение O (1) и не полагается на прохождение списка строк. Конечно, вам нужно построить этот словарь, и это, вероятно, стоит больше.

Возможно, имеет смысл добавить простой метод bool ContainsCase(string aCase) который просто вызывает метод ContainsKey словаря.

  • Является ли «переключатель» быстрее, чем «если»?
  • Почему оператор switch не может применяться к строкам?
  • Почему ваш тип данных оператора switch не может быть длинным, Java?
  • Использование двух значений для одного оператора case switch
  • Использовать «переход» в коммутаторе?
  • Использование Case / Switch и GetType для определения объекта
  • Как выбрать диапазон значений в инструкции switch?
  • Использовать строку в корпусе переключателя в java
  • Оператор переключения Java несколько случаев
  • Если против скорости переключения
  • Почему я не могу использовать оператор switch на String?
  • Давайте будем гением компьютера.