Як ви, мабуть, знаєте, зниження двох рядків та їх порівняння - це не те саме, що робити порівняння з ігноруванням регістру. Для цього існує маса причин. Наприклад, стандарт Unicode дозволяє кодувати текст із діакритикою кількома способами. Деякі символи включають як базовий символ, так і діакритичний знак в одній кодовій точці. Ці символи також можуть бути представлені як базовий символ, за яким слідує комбінуючий діакритичний символ. Ці два подання є рівними для всіх цілей, і порівняння рядків з урахуванням культури в .NET Framework правильно визначить їх рівними або з CurrentCulture, або з InvariantCulture (з IgnoreCase або без нього). Порядкове порівняння, навпаки, неправильно вважатиме їх нерівними.
На жаль, switch
не робить нічого, крім порядкового порівняння. Порядкове порівняння добре для деяких типів програм, наприклад, аналіз файлу ASCII із жорстко визначеними кодами, але порядкове порівняння рядків є неправильним для більшості інших застосувань.
Те, що я робив раніше, щоб отримати правильну поведінку, - це просто макет мого власного висловлення перемикача. Існує безліч способів зробити це. Одним із способів було б створити List<T>
пару пар рядків справи та делегатів. Шукати у списку можна за допомогою відповідного порівняння рядків. Коли збіг буде знайдено, тоді може бути викликаний пов'язаний делегат.
Інший варіант - зробити очевидний ланцюжок if
тверджень. Зазвичай це виявляється не так погано, як це звучить, оскільки структура дуже регулярна.
Чудовим у цьому є те, що насправді немає покарання за продуктивність у знущанні над власною функцією комутатора при порівнянні з рядками. Система не збирається створювати таблицю стрибків O (1) так, як це можна з цілими числами, тому вона все одно буде порівнювати кожен рядок по одному.
Якщо існує багато випадків для порівняння, і продуктивність є проблемою, тоді List<T>
описаний вище варіант можна замінити відсортованим словником або хеш-таблицею. Тоді продуктивність може потенційно збігатися або перевищувати опцію оператора перемикання.
Ось приклад списку делегатів:
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()
? Крім того, він не порівнює два невідомі рядки , він порівнює один невідомий рядок з одним відомим рядком. Таким чином, до тих пір, поки він знає, як правильно кодувати відповідне подання верхнього чи нижнього регістру, тоді блок перемикачів повинен працювати нормально.