Недопустимый код, обнаруженный в операторе case
У меня есть код:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.Alt|Keys.D1:
if (this._condition1)
{
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
break;
case Keys.Control |Keys.U:
if (this._condition2)
{
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
break;
default:
return base.ProcessCmdKey(ref msg, keyData);
}
return true;
Это дает мне предупреждение "недостижимый код обнаружено" при разрывах.
Хорошая практика не использовать здесь оператора break? Я не хочу отключать предупреждение "недостижимый код".
PS: В моем методе ProcessCmdKey существует много case.
Ответы
Ответ 1
В коде есть три недостижимых оператора, первые два - это инструкции break, а последняя строка int last last, возвращающая true, также недостижима, я не знаю, обнаруживает ли это компилятор С# или нет, но логически нет также будет достигнуто конечное выражение о возврате.
Существует несколько способов решения этой проблемы,
- Храните временную переменную, называемую bool retVal, сохраняйте retVal и разбивайте ваш случай с коммутатором, а в конце возврата функции retVal.
- Если вы возвращаете значение до разрыва, оператор break бесполезен.
Лучший способ дизайна
Если вы возвращаете значения в случаях коммутатора, может быть сложно проанализировать ваш код позже вами или кем-то другим, обычно лучше сохранить переменную temp возвращаемого значения и вернуть ее в конце функции, что становится легче отлаживать и понимать код для нового кодера.
Коммутатор может быть сложным, и больше возвратов внутри коммутатора может не иметь лучшего контроля, если вы хотите реализовать ведение журнала, отладки, возврат из случаев может быть сложным. И это становится способом сложного просмотра графиков логических потоков.
Итак, лучше избегать возврата из корпуса, но все же это зависит от ситутаций. Здесь нужно сделать разумное решение.
Ответ 2
break
не требуется, если все пути в инструкции case
заканчиваются на return
. Не используйте его тогда, иначе вы получите упомянутое предупреждение.
Ответ 3
В этом случае хорошей практикой imho было бы закончить каждый случай возвратом, например:
case Keys.Alt|Keys.D1:
bool result;
if (this._condition1)
{
result = true;
}
else
{
result = base.ProcessCmdKey(ref msg, keyData);
}
return result;
или
case Keys.Alt|Keys.D1:
bool result = (this._condition1)
? true
: base.ProcessCmdKey(ref msg, keyData);
return result;
Ответ 4
Нет ничего плохого в том, что здесь вызывается инструкция break
.
Ответ 5
Вы используете возврат в обоих условиях. Таким образом, разрыв можно легко удалить.
Но я предпочитаю оставить его там, если вы когда-нибудь измените свой код.
Ответ 6
Как и удаление строк break;
оттуда, вы также можете удалить инструкции else. Это ненужно, так как вы возвращаетесь с первого if
.
Таким образом, ваш код может выглядеть следующим образом:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.Alt|Keys.D1:
if (this._condition1)
return true;
return base.ProcessCmdKey(ref msg, keyData);
case Keys.Control |Keys.U:
if (this._condition2)
return true;
return base.ProcessCmdKey(ref msg, keyData);
default:
return base.ProcessCmdKey(ref msg, keyData);
}
return true;
}
Вы можете уменьшить его еще больше, удалив строки return true;
и инвертируя ваши операторы if, потому что вы все равно вернете истину и конец метода:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
switch (keyData)
{
case Keys.Alt|Keys.D1:
if (!this._condition1)
return base.ProcessCmdKey(ref msg, keyData);
break;
case Keys.Control |Keys.U:
if (!this._condition2)
return base.ProcessCmdKey(ref msg, keyData);
break;
default:
return base.ProcessCmdKey(ref msg, keyData);
}
return true;
}
EDIT: Я забыл, что вы не можете провалиться с помощью С#, чтобы в каждом случае вам понадобился break;. Какой вид руин хорошо читает этот блок.
Ответ 7
Оператор break никогда не будет выполнен, потому что вы вернетесь из метода. Поэтому я предлагаю удалить ненужный разрыв.
Ответ 8
Опыт Bitter научил меня всегда включать инструкции break, если вы действительно не хотите перейти к следующему утверждению и даже тогда комментировать его. В противном случае функция могла бы вести себя по-разному, потому что другой разработчик что-то изменил поздно вечером в пятницу и не видел пропавшего перерыва.
Если функция - пусть и большая - соответствует той же, если... return... else.... возвращает структуру на всем протяжении, вы можете определить переменную кода возврата в начале функции. Затем назначьте его в своем случае и верните его в конце, независимо от того, какое значение оно окажется.
Ответ 9
Вы можете переписать свой код намного короче и менее репатативным:
bool ret = false;
switch(keyDate){
case Keys.Alt | Keys.D1:
ret = this._condition1;
break;
case Keys.Control |Keys.U:
ret = this._condition2;
break;
default: break;
}
return ret || base.ProcessCmdKey(ref msg, keyData);
Ответ 10
Существует определенное недоразумение, что все блоки case
в С# switch
должны заканчиваться на break
. Фактически они должны заканчиваться инструкцией перехода во всех кодах кода; это может быть break
, return
, goto
или даже continue
(или throw
, конечно). Поскольку компилятор будет вызывать ошибку, если есть путь к коду без инструкции перехода, нет абсолютно никакой причины для окончательного break
в примере. Компилятор не позволит вам изменить код на версию, в которой будет достигнуто окончательное break
, и это будет момент, чтобы добавить его.
Ответ 11
Здесь вообще не требуется инструкция переключателя, вообще избегая проблемы:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
return
(keyData == Keys.Alt|Keys.D1 && this._condition1) ||
(keyData == Keys.Control|Keys.U && this._condition2) ||
base.ProcessCmdKey(ref msg, keyData);
}
Ответ 12
В качестве кода в настоящий момент команды "break" никогда не будут выполняться и не будут выполнены окончательная команда "return true". Удаление этих файлов избавит вас от предупреждений.
Возможно, вы захотите попробовать решение с меньшим количеством обратных путей, так как он может сделать код более сложным для отладки и понимания. Что-то вроде этого:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool processed = false;
switch (keyData)
{
case Keys.Alt | Keys.D1:
if (this._condition1)
processed = true;
break;
case Keys.Control | Keys.U:
if (this._condition2)
processed = true;
break;
}
if (!processed)
processed = base.ProcessCmdKey(ref msg, keyData);
return processed;
}
Ответ 13
Я понимаю, что это не отвечает на вопрос напрямую, но вдохновленный различными ответами здесь, я просто хотел добавить еще одну вариацию о том, как можно "структурировать" "переключатель":
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Alt|Keys.D1 && _condition1)
return true;
if (keyData == Keys.Control|Keys.U && _condition2)
return true;
// ...repeat for other variations
return base.ProcessCmdKey(ref msg, keyData);
}
Ответ 14
В соответствии с вашим кодом все перерывы и последнее утверждение никогда не достигаются, поскольку перед ними есть операторы return.
Вы можете переписать свой код следующим образом:
switch (keyData)
{
case Keys.Alt|Keys.D1:
if (this._condition1) return true;
else goto default;
case Keys.Control |Keys.U:
if (this._condition2) return true;
else goto default;
default:
return base.ProcessCmdKey(ref msg, keyData);
}