Как обрабатывать "не все пути кода возвращают значение", когда логика функции обеспечивает возврат

Я полагаю, что самый простой способ объяснить это - надуманный пример:

public static int Fail() {
    var b = true;
    if (b) {
        return 0;
    }
}

Этот код не будет компилироваться, и выдает ошибку "не все пути кода возвращают значение", в то время как мы, люди, ясно видим, что это так. Я понимаю почему. Мой вопрос: что нужно сделать, чтобы исправить ситуацию. Это может быть что-то вроде этого:

public static int Fail() {
    var b = true;
    if (b) {
        return 0;
    }
    throw new ApplicationException("This code is unreachable... but here we are.");
}

Но все это кажется довольно глупым. Есть ли способ лучше? Опять же, этот код является надуманным примером (и может быть сокращен до return 0). Мой настоящий код является массивным и сложным, но логически (с помощью математического доказательства) возвращает значение, прежде чем пытаться выйти.

6 ответов

Решение

Анализ потока кода в C# ограничен, и, как показывает ваш пример, есть случаи, когда все пути возвращаются, но компилятор не может его обнаружить. Бросок исключения является приемлемым средством правовой защиты в этих обстоятельствах.

Я бы не использовал возврат значения по умолчанию, чтобы исправить эту ошибку. Вы работаете в предположении, что эта строка никогда не противоречит совету компилятора. Подумайте на секунду, что ваш анализ неверен и выполнение может продолжаться до конца метода. Если вы вернете значение по умолчанию, у вас не будет никаких признаков проблемы. Метод будет просто возвращать неверные данные. Бросив исключение, вы поймете, что есть проблема.

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

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

Компилятор не выполняет сложные математические процессы, чтобы гарантировать, что вы возвращаете значение, это относительно тупой зверь в этом отношении.

Если вы уверены в своих предположениях, просто добавьте return 0; в конце с комментарием, заявляющим реальность, что это никогда не будет достигнуто.

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

Действительно поздний ответ, но я могу представить сценарий, в котором функция не будет знать, что возвращать:

1) Выполнить шаг за шагом, используя отладчик

2) Перешагни var b = true;

3) Когда if (b) { достигнуто, положить b = false в часах. Оба вернутся false и назначить b = false

4) Перешагни if)

5) Конец функции достигнут, возврата нет

С этой точки зрения return явно необходимо.

У меня был код, подобный этому, и я исправил его таким образом. Глядя на ваш пример:

public static int Fail() {
    var b = true;
    if (b) {
        return 0;
    }
    throw new ApplicationException("This code is unreachable... but here we are.");
}

станет

public static int Fail() {
    var b = true;
    if (!b) {
        throw new ApplicationException("This code is unreachable... but here we are.");
    }
    return 0;
}

Это избавит от предупреждения компилятора, по-прежнему будет логически таким же, и на самом деле будет немного более чистым кодом.

Обычно есть пара классов программистов:

  1. Те, кто возвращается во всем.
  2. Они, которые возвращаются только в конце функции / метода.

Первый подход:

public static int Fail() {
  var b = true;
  if (b)
    return 0;

  return 1;
}

Я обычно предпочитаю второй подход, так как легче быстро увидеть, где возвращается функция / метод.

public static int Fail() {
  var b = true;
  var returnValue = 1:
  if (b)
    returnValue = 0;

  return returnValue;
}
Другие вопросы по тегам