PowerShell — почему исключение Divide By Zero не перехватывается?

На моей машине каждый из следующих фрагментов кода выдает исключение вместо вывода на стандартный вывод «1» и «2». Почему исключение не перехватывается?

try {
    [int]$a = 1/0
}
catch {
    write 1
}
finally {
    write 2
}

try {
    [int]$a = 1/0
}
catch [System.Exception] {
    write 1
}
finally {
    write 2
}

person Oz Molaim    schedule 16.05.2012    source источник


Ответы (3)


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

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

try {
    $divisor = 0
    [int]$a = 1/$divisor
}
catch {
    write 1
}
finally {
    write 2
}

Из Windows PowerShell в действии (стр. 257)

В данном примере используется 1/$null. Причина, по которой это делается вместо простого 1/0, заключается в том, что интерпретатор PowerShell выполняет нечто, называемое сворачиванием константных выражений.

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

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

person Lieven Keersmaekers    schedule 16.05.2012

Исключение RuntimeException в версии 2 невозможно отловить. Это было исправлено в v3.

Деление на ноль относится к этой категории.

person BartekB    schedule 16.05.2012
comment
Итак... мой плохой. :) Это не было RuntimeException. Я только что скопировал FullyQualifiedErrorId, и он не содержит деталей, важных для этого сценария. Что касается v3: я не могу найти ссылку (пока). Дуг Финке упомянул этот расчет в качестве примера в своей готовящейся к выходу книге PowerShell для разработчиков, поэтому я попробовал и понял, что в версии 3 его действительно можно перехватить. Извините за путаницу, вызванную использованием неправильной терминологии... :) - person BartekB; 16.05.2012
comment
Спасибо за обновление. Если вы найдете ссылку, я надеюсь, что вы все равно опубликуете ее здесь. - person Lieven Keersmaekers; 18.05.2012
comment
Хорошо, не уверен, почему я не заметил этого раньше... Посмотрите примечания к выпуску WMF 3.0, стр. 13. Там есть информация об этом конкретном случае: Свертывание констант не выполняется во время синтаксического анализа. И позже, в колонке Error Message No parsing. Ошибка обнаруживается во время выполнения. Очевидно, что при этом мы получаем возможность поймать эту ошибку. Примечания к выпуску WMF 3.0 RC можно найти здесь: microsoft.com /en-us/download/details.aspx?id=29939 - person BartekB; 04.06.2012

Вы можете попытаться создать исключение с помощью такой строки: trap { "Your Exception" } 1/0
Это вызовет исключение «разделить на 0». Хотя я действительно не понимаю, почему ваш код не генерирует исключение ._.
PS: Разве это не должно быть catch [System.SystemException] ? :)

person Depado    schedule 16.05.2012