Падение заявления переключателя - одна из моих личных главных причин любить switch
против if/else if
конструкций. Пример в порядке здесь:
static string NumberToWords(int number)
{
string[] numbers = new string[]
{ "", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine" };
string[] tens = new string[]
{ "", "", "twenty", "thirty", "forty", "fifty",
"sixty", "seventy", "eighty", "ninety" };
string[] teens = new string[]
{ "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen" };
string ans = "";
switch (number.ToString().Length)
{
case 3:
ans += string.Format("{0} hundred and ", numbers[number / 100]);
case 2:
int t = (number / 10) % 10;
if (t == 1)
{
ans += teens[number % 10];
break;
}
else if (t > 1)
ans += string.Format("{0}-", tens[t]);
case 1:
int o = number % 10;
ans += numbers[o];
break;
default:
throw new ArgumentException("number");
}
return ans;
}
Умные люди цепляются, потому что string[]
s должны быть объявлены вне функции: ну, они есть, это только пример.
Компилятор завершается с ошибкой:
Контроль не может перейти от одной метки кейса ('case 3:') к другой Элемент управления не может перейти от одной метки кейса ('case 2:') к другой
Почему? И есть ли способ получить такое поведение, не имея три if
с?
c#
switch-statement
Мэтью Шарли
источник
источник
«Почему» состоит в том, чтобы избежать случайного провала, за что я благодарен. Это не редкий источник ошибок в C и Java.
Обходной путь должен использовать goto, например
Общий дизайн переключателя / корпуса немного неудачен, на мой взгляд. Он застрял слишком близко к C - есть некоторые полезные изменения, которые могут быть сделаны с точки зрения области видимости и т. Д. Возможно, был бы полезен более разумный переключатель, который мог бы выполнять сопоставление с образцом и т. Д., Но это действительно переключение с переключателя на «проверку последовательности условий» - в этот момент может потребоваться другое имя.
источник
if (result = true) { }
Падение коммутатора исторически является одним из основных источников ошибок в современном программном обеспечении. Разработчик языка решил сделать обязательным переход в конце дела, если только вы не выполняете переход к следующему делу напрямую без обработки.
источник
case 1, 2:
на языках, которые позволяют это. То, что я никогда не пойму, - это то, почему любой современный язык не хотел бы позволить это.case 1, 2:
это один ярлык, но с несколькими именами. - FWIW, я думаю, что большинство языков, которые запрещают проваливаться, не являются специальным регистром с указателем «последовательные метки регистра», а рассматривают метки регистра как аннотацию к следующему оператору и требуют последнего оператора перед оператором, помеченным (один или больше) кейсы для прыжков.Чтобы добавить здесь ответы, я думаю, что стоит рассмотреть противоположный вопрос в связи с этим, а именно. почему C позволил провалиться в первую очередь?
Любой язык программирования, конечно, преследует две цели:
Поэтому создание любого языка программирования - это баланс между тем, как наилучшим образом служить этим двум целям. С одной стороны, чем проще превратить в компьютерные инструкции (будь то машинный код, байт-код, такой как IL, или инструкции интерпретируются при исполнении), тем больше вероятность того, что процесс компиляции или интерпретации будет эффективным, надежным и компактный в выходе. В крайнем случае, эта цель приводит к тому, что мы просто пишем на ассемблере, IL или даже на необработанных кодах операций, потому что самая простая компиляция - это когда компиляция вообще отсутствует.
И наоборот, чем больше язык выражает намерение программиста, а не средства, использованные для этой цели, тем более понятна программа как при написании, так и во время обслуживания.
Теперь
switch
его всегда можно было скомпилировать, преобразовав его в эквивалентную цепочкуif-else
блоков или аналогичную, но он был спроектирован как позволяющий компилировать в конкретный общий шаблон сборки, где каждый принимает значение, вычисляет смещение из него (будь то путем просмотра таблицы индексируется идеальным хэшем значения или фактической арифметикой значения *). Стоит отметить, что сегодня компиляция C # иногда превращаетсяswitch
в эквивалентif-else
, а иногда использует подход перехода на основе хеша (и аналогично с C, C ++ и другими языками с сопоставимым синтаксисом).В этом случае есть две веские причины для разрешения провала:
В любом случае это происходит естественным образом: если вы строите таблицу переходов в набор инструкций, а одна из более ранних групп инструкций не содержит какой-либо переход или возврат, то выполнение просто естественным образом переходит в следующий пакет. Разрешение
switch
провала было бы то, что «просто произошло бы», если бы вы превратили -using C в таблицу переходов - используя машинный код.Программисты, которые писали на ассемблере, уже привыкли к эквиваленту: при написании таблицы переходов вручную на ассемблере им нужно было бы решить, закончится ли данный блок кода возвратом, переходом за пределы таблицы или просто продолжением к следующему блоку. Таким образом, добавление явного кода в
break
случае необходимости было «естественным» и для кодера.Поэтому в то время это была разумная попытка сбалансировать две цели компьютерного языка, поскольку они касаются как создаваемого машинного кода, так и выразительности исходного кода.
Спустя четыре десятилетия, все по-разному, по нескольким причинам:
switch
что они будут превращены вif-else
тот, который считается наиболее эффективным, или же превращается в особенно эзотерический вариант подхода с использованием таблицы переходов, выше. Соотношение между подходами более высокого и более низкого уровня не так сильно, как это было раньше.switch
блоков используют провал, отличающийся от нескольких меток в одном блоке, и считалось, что использование Случай здесь означал, что эти 3% были на самом деле намного выше, чем обычно). Таким образом, изучаемый язык делает необычное более легким в обращении, чем обычный.В связи с этими двумя последними пунктами рассмотрим следующую цитату из текущей редакции K & R:
Таким образом, изо рта лошади, падение в C проблематично. Хорошей практикой всегда является документирование ошибок с комментариями, что является применением общего принципа, согласно которому следует документировать, когда кто-то делает что-то необычное, потому что это поможет избежать более поздней проверки кода и / или сделать ваш код похожим на него. есть ошибка новичка в этом, когда это на самом деле правильно.
И когда вы думаете об этом, код так:
Является ли добавить что - то , чтобы сделать падение-через явное в коде, это просто не то , что можно обнаружить (или отсутствие которых может быть обнаружен) компилятором.
Таким образом, тот факт, что on должен быть явным с переходом в C #, не добавляет никаких штрафов тем, кто хорошо писал на других языках стиля C, так как они уже были бы явными в своих переходах. †
Наконец, использование
goto
здесь уже является нормой для C и других таких языков:В этом случае, когда мы хотим, чтобы блок был включен в код, выполняемый для значения, отличного от только того, которое приводит его к предыдущему блоку, мы уже должны его использовать
goto
. (Конечно, есть способы и способы избежать этого с помощью различных условных обозначений, но это верно практически обо всем, что касается этого вопроса). Таким образом, C # построен на уже нормальном способе справиться с одной ситуацией, когда мы хотим использовать более одного блока кода в aswitch
, и просто обобщить его, чтобы охватить также и провал. Это также сделало оба случая более удобными и самодокументируемыми, так как мы должны добавить новую метку в C, но можем использоватьcase
как метку в C #. В C # мы можем избавиться отbelow_six
метки и использовать,goto case 5
что более понятно относительно того, что мы делаем. (Мы также должны были бы добавитьbreak
для тогоdefault
, что я пропустил только для того, чтобы сделать приведенный выше код C явно не кодом C #).Таким образом, в итоге:
break
, но и для более легкого изучения языка теми, кто знаком с подобными языками, и для облегчения портирования.goto
подход, основанный на том же самом, что и для удара по одному и тому же блоку из разныхcase
меток, что и в C. Он просто обобщает его в некоторых других случаях.goto
подход более удобным и понятным, чем в C, позволяяcase
операторам выступать в качестве меток.В общем, довольно разумное дизайнерское решение
* Некоторые формы BASIC позволяют делать то,
GOTO (x AND 7) * 50 + 240
что, будучи хрупким и, следовательно, особенно убедительным аргументом в пользу запретаgoto
, служит для показа эквивалента на более высоком языке, чем способ, которым код низкого уровня может совершить переход на основе арифметическое значение, которое гораздо более разумно, когда это результат компиляции, а не что-то, что должно быть сохранено вручную. Реализации Устройства Даффа, в частности, хорошо подходят для эквивалентного машинного кода или IL, потому что каждый блок инструкций часто будет одинаковой длины без необходимости добавленияnop
наполнителей.† Устройство Даффа снова появляется здесь, как разумное исключение. Тот факт, что с этим и аналогичными шаблонами происходит повторение операций, делает использование сквозного перехода относительно ясным даже без явного комментария на этот счет.
источник
Вы можете «перейти к метке кейса» http://www.blackwasp.co.uk/CSharpGoto.aspx
источник
Они пропустили это поведение по своему замыслу, чтобы избежать, когда оно не использовалось по воле, но вызывало проблемы.
Его можно использовать только в том случае, если в части кейса нет оператора, например:
источник
Они изменили поведение оператора switch (из C / Java / C ++) для c #. Я предполагаю, что причина была в том, что люди забыли о провале и были вызваны ошибки. В одной книге, которую я прочитал, говорится, что для симуляции используется goto, но это не похоже на хорошее решение для меня.
источник
goto case
, для чего. Его преимущество перед прорывом в том, что оно явное. То, что некоторые люди здесь возражают противgoto case
того, чтобы просто показать, что они были внушены против "goto" без какого-либо понимания проблемы и неспособны думать самостоятельно. Когда Дейкстра написал «GOTO рассмотрено как вредное», он обращался к языкам, у которых не было никаких других средств изменения потока управления.goto
может быть оптимизация кода?Вы можете добиться провала как c ++ с помощью ключевого слова goto.
EX:
источник
- C # switch () документация
источник
После каждого оператора case требуется оператор break или goto, даже если это случай по умолчанию.
источник
Просто небольшое замечание, чтобы добавить, что компилятор для Xamarin на самом деле ошибся, и это позволяет провалиться. Предположительно это было исправлено, но не было выпущено. Обнаружил это в некотором коде, который на самом деле проваливался, и компилятор не жаловался.
источник
переключатель (C # Reference) говорит
Так что вам также нужно добавить a
break;
в вашdefault
раздел, иначе все равно будет ошибка компилятора.источник
C # не поддерживает падение с помощью операторов switch / case. Не уверен, почему, но на самом деле нет никакой поддержки для этого. связь
источник
goto case
. Это был намеренный, мудрый выбор дизайна дизайнерами C #.Вы забыли добавить «перерыв»; утверждение в случае 3. В случае 2 вы записали его в блок if. Поэтому попробуйте это:
источник