Вернуться в блок «Наконец». Почему бы и нет?

Как MSDN упоминает:

Код в блоке finally выполняется после того, как будет встречен оператор Return в блоке Try или Catch, но до того, как будет выполнен этот оператор Return. В этой ситуации оператор Return в блоке finally выполняется перед исходным оператором Return. Это дает другое возвращаемое значение. Чтобы предотвратить эту потенциально запутанную ситуацию, избегайте использования операторов Return в блоках finally.

Поскольку я многого не понял из этой заметки, я возьму пример (VB.NET, я думаю, что в C # ситуация аналогичная):

Try
    HugeOp()
    Return "OK"
Catch
    Return "NOK"
Finally
    Return "Finally"
End Try

Теперь, почему это должно быть незаконным как в C #, так и в VB.NET?


person serhio    schedule 26.04.2011    source источник
comment
что происходит, когда вы его запускаете?   -  person Mitch Wheat    schedule 26.04.2011
comment
Как я всегда рекомендую, просто сделайте небольшую тестовую программу, чтобы смоделировать случай и убедиться в этом сами.   -  person Dmitry    schedule 26.04.2011
comment
это незаконно в C # (edit: и, похоже, VB)   -  person Marc Gravell    schedule 26.04.2011
comment
@serhio: вот и ваш ответ   -  person Mitch Wheat    schedule 26.04.2011
comment
@Marc Gravell: это также незаконно в VB.NET.   -  person serhio    schedule 26.04.2011
comment
@Mitch Wheat: Вопрос был ПОЧЕМУ вот это   -  person serhio    schedule 26.04.2011
comment
Я не уверен, что понимаю задаваемый вопрос. Вы запускали код? Что это вернуло?   -  person izb    schedule 26.04.2011
comment
@serhio а, тогда MSDN сбивает с толку; Лучшее замечание в MSDN - избегать использования операторов Return в блоках finally, иначе ваш код не будет компилироваться; Я аннотировал MSDN по этому поводу.   -  person Marc Gravell    schedule 26.04.2011
comment
comment
@Marc Gravell ♦: Почему обычно упоминаются такие фразы, как избегать использования возврата из блоков метода, иначе ваш код не будет компилироваться? Вместо этого фраза типа The .NET compilers (C#, VB) does not allow the using of "Return" in the finally locks, because of bla bla... была бы более подходящей ...   -  person serhio    schedule 26.04.2011
comment
@ Мэтт Эллен: 2 разных вопроса   -  person serhio    schedule 26.04.2011
comment
@serhio - примечание в MSDN действительно дает обоснование. Я считаю, что этого нельзя избегать (что звучит как рекомендация); это не сработает   -  person Marc Gravell    schedule 26.04.2011
comment
@Marc Gravell ♦: Я, да, это была моя точка зрения. Но ваше лучшее замечание по-прежнему сохраняет слово избегания ...)   -  person serhio    schedule 27.04.2011
comment
Интересное примечание: это не незаконно в JavaScript. function m() { try { return 1; } finally { return 2; } } вызов m() вернет 2. Реализация этого была настоящей головной болью для команды разработчиков. Это также законно на Java.   -  person Eric Lippert    schedule 16.04.2013


Ответы (3)


Это незаконно, потому что при достижении блока Finally возвращаемое значение уже определено («ОК», если все прошло хорошо, «NOK», если было обнаружено исключение). Если бы вы смогли вернуть другое значение из блока Finally, это значение будет возвращаться всегда независимо от результата приведенных выше инструкций. Это просто не имело бы смысла ...

person Thomas Levesque    schedule 26.04.2011
comment
Спасибо. Итак, наконец, должно быть возвращаемое значение. Сделано незаконным, чтобы расшифровать код. - person serhio; 26.04.2011
comment
Нет, возвращаемое значение устанавливается до выполнения оператора возврата. Между этими двумя действиями выполняется блок finally. Поэтому нет смысла иметь оператор return в блоке finally. Нет смысла говорить, что возвращаемое значение должно быть наконец, потому что не имеет смысла иметь возвращаемое значение. - person izb; 26.04.2011
comment
@izb: Другими словами, в моем успешном случае компилятор принимает ОК в качестве возвращаемого значения, выполняет блок finally, затем принимает ОК и фактически возвращает его? - person serhio; 26.04.2011
comment
Спецификация может определять поведение return в операторе finally как угодно. Он может возвращать старое возвращаемое значение, новое возвращаемое значение или быть недопустимым. Любые, если такое поведение возможно, и они решили сделать его незаконным. И я согласен с этим решением. - person CodesInChaos; 26.04.2011
comment
Это не имеет ничего общего с уже установленным возвращаемым значением. Вы можете удалить первые два возврата, и вы получите ту же ошибку. - person usr; 26.06.2016
comment
@usr, если у вас есть лучшее объяснение, не стесняйтесь публиковать ответ;) - person Thomas Levesque; 26.06.2016
comment
Не требуется публиковать ответ, чтобы указать на недостаток в существующем. - person usr; 26.06.2016
comment
@usr, действительно. Чтобы дать более полезный ответ на ваш комментарий, то, что вы сказали, верно, но учтите следующее: имеет смысл запретить return в finally, если вы уже вернули что-то в try или catch; это может быть разрешено, если вы ничего не вернули в try или catch, но это было бы несовместимо. Я думаю, что разработчики языка просто хотели избежать несоответствия. Конечно, это только мое предположение; чтобы узнать истинную причину, вам придется спросить самих разработчиков языка;) - person Thomas Levesque; 26.06.2016

Мне было любопытно, я использую VS2010 и не разрешаю возврат в блоке finally. вот код, который я скомпилировал

Public Class Class1
   Public Shared Function test() As String
      Try
         Return "OK"
      Catch ex As Exception
         Return "Catch"
      Finally
         test = "Finally"
      End Try
   End Function
End Class

Я скомпилировал DLL для просмотра MSIL, это выглядело довольно интересно, приведенный выше код в основном реорганизован под это:

Public Class Class2
   Public Shared Function test() As String
      Try
         Try
            test = "OK"
         Catch ex As Exception
            test = "Catch"
         End Try
      Finally
         test = "Finally"
      End Try

      Return test
   End Function
End Class

и проверяя это, MSIL для двух вышеупомянутых классов точно такой же.

person Apeiron    schedule 28.10.2011
comment
Итак, наконец, вы нашли способ вернуться в блок finally в Visual Basic, используя имя функции, даже если это сбивает с толку, есть способ сделать это ... - person serhio; 21.04.2013

Думаю, ответ в вопросе. Это незаконно, потому что это сбивает с толку. Неизвестно, какое значение будет возвращено. Если это незаконно, вы вынуждены писать код, в котором поток будет намного понятнее.

person izb    schedule 26.04.2011
comment
сбивает с толку, интуитивно понятно, но на самом деле, что должно быть здесь после правил компилятора? Всегда ли это в конце? - person serhio; 26.04.2011
comment
Похоже, что правила компилятора заявляют, что это незаконно и не должно компилироваться. Так что вопрос, что он возвращает, не имеет смысла. - person CodesInChaos; 26.04.2011
comment
@CodeInChaos: прочтите записку, которую я опубликовал. Это дает другое возвращаемое значение. - person serhio; 26.04.2011
comment
Ваше примечание явно неточно и не описывает поведение C # или VB.net. Вот почему @MarcGravell предложил обновить документацию, чтобы она соответствовала фактическому поведению компилятора. - person CodesInChaos; 26.04.2011
comment
@CodeInChaos: я не уверен, что в Visual Studio этот вид ошибки нельзя было преобразовать в предупреждение ... - person serhio; 26.04.2011
comment
Создание предупреждения нарушило бы спецификацию. 8.9.4 Оператор return - это ошибка времени компиляции, когда оператор return появляется в блоке finally (из спецификации C #). - person CodesInChaos; 26.04.2011