Подтвердить что ты не робот

Недопустимый код, обнаруженный в операторе 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.

4b9b3361

Ответ 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);
    }