TRY FINALLY EXCEPT — различия между версиями

Материал из GB wiki
Перейти к: навигация, поиск
 
(не показано 16 промежуточных версий этого же участника)
Строка 2: Строка 2:
 
{{Функция ГБ
 
{{Функция ГБ
 
|Название=TRY...FINALLY...EXCEPT
 
|Название=TRY...FINALLY...EXCEPT
|Описание=Функции для работы с ошибками.
+
|Описание=Функции для обработки исключений (доступны с версии 1.9.0.9).
|Синтаксис='''TRY'''(''выражение, выражение, ...'', '''FINALLY'''(''выражение, выражение, ...'') или '''EXCEPT'''(''выражение, выражение, ...''))
+
|Синтаксис='''TRY'''(''выражение, выражение, ...'', '''FINALLY'''(''выражение, выражение, ...'') )
 +
<br/>или
 +
<br/>'''TRY'''(''выражение, выражение, ...'', '''EXCEPT'''(''выражение, выражение, ...'') )
 +
<br/>или
 +
<br/>'''TRY'''(''выражение, выражение, ...'', '''EXCEPT'''(''выражение, выражение, ...'', '''RAISE'''() ) )
 
|Аргументы=
 
|Аргументы=
 
{{Аргумент
 
{{Аргумент
  |Название=Имя контейнера
+
  |Название=блок TRY
  |Пояснение=имя контейнера, для которого устанавливается порядок обхода. Если задана пустая строка - порядок обхода устанавливается во всей форме.
+
  |Пояснение=в блоке TRY находятся выражения, выполнение которых нужно проконтролировать
 
}}<br/>{{Аргумент
 
}}<br/>{{Аргумент
  |Название=Способ обхода
+
  |Название=блок FINALLY
  |Пояснение=кодовое слово, определяющее способ обхода полей. Может принимать одно из значений:
+
  |Пояснение=в блоке FINALLY находятся выражения, которые нужно выполнить независимо от того, возникло или нет исключение при выполнении блока TRY. Обычно используется для гарантированного освобождения ресурсов, выделенных в блоке TRY.<br>Фактически FINALLY не обрабатывает исключение, т.е. скрипт будет прерван, если нет никаких обработчиков EXCEPT. Чтобы всё-таки обработать исключение, нужно использовать вложенные конструкции TRY:
 +
TRY(
 +
  TRY(
 +
    ...,
 +
    EXCEPT(
 +
      ...
 +
    )
 +
  ),
 +
  FINALLY(
 +
    ...
 +
  )
 +
)
 +
}}<br/>{{Аргумент
 +
|Название=блок EXCEPT
 +
|Пояснение=в блоке EXCEPT находятся выражения, которые будут выполнены только в том случае, если в блоке TRY возникнет исключение. При этом исключение считается обработанным и выполнение скрипта не прерывается стандартным сообщением об ошибке
 +
}}<br/>{{Аргумент
 +
|Название=RAISE()
 +
|Пояснение=функция RAISE(), помещённая в блок EXCEPT, возобновляет исключение, проталкивая его во внешний обработчик или, если такового нет - в стандартный обработчик исключений
 +
}}<br/>{{Аргумент
 +
|Название=Объект E
 +
|Пояснение=E - объект для работы с ошибками. Например: E.ClassName(), E.Message(), E.DbMessage().<br>E.DbMessage() содержит оригинальное сообщение из процедуры, если ошибка была при вызове процедуры, либо то же самое что E.Message() во всех остальных случаях
 
}}
 
}}
|Пример=TRY(
+
|Пример=Пример 1.
<br/>    /*Защищаемые*/,
+
:SDt:=`aaa`,
<br/>    /*выражения*/
+
'''TRY'''(STRTODATE(:SDt),
<br/>    FINALLY(
+
    '''EXCEPT'''(
<br/>        Info(`Всегда свобождаем ресурсы`)
+
        INFO(`Ошибка преобразования даты`)
<br/>    )
+
    )
<br/>  ),
+
),
<br/EXCEPT(
+
INFO(`Продолжаем выполнение...`)
<br/>    Info(`Ругаемся на ашипку!`),
+
 
<br/>   RAISE()
+
Будут выведены следующие сообщения:
<br/>  )
+
* "Ошибка преобразования даты"
<br/> ),
+
* "Продолжаем выполнение..."
<br/> Info(`Опаньки, продолжаем выполнение!`)
+
и выполнение скрипта будет продолжено.
 +
 
 +
<br>
 +
Пример 2.
 +
:SDt:=`aaa`,
 +
'''TRY'''(STRTODATE(:SDt),
 +
  '''EXCEPT'''(
 +
    INFO(`Ошибка преобразования даты`),
 +
    '''RAISE'''()
 +
  )
 +
),
 +
INFO(`Продолжаем выполнение...`)
 +
 
 +
Будут выведены следующие сообщения:
 +
* "Ошибка преобразования даты"
 +
* "'aaa' is not a valid date and time"
 +
и выполнение скрипта будет прервано.
 +
 
 +
<br>
 +
Пример 3.
 +
'''TRY'''(
 +
  /*распределяем ресурсы*/
 +
  :var.str:=TStringList.Create(),
 +
  /*попытка прочитать несуществующий файл*/
 +
  :var.str.LoadFromFile(`C:\0.txt`),
 +
  '''FINALLY'''(
 +
    /*ВСЕГДА освобождаем ресурсы*/
 +
    :var.str.Free(),
 +
    INFO(`Освободили ресурсы`)
 +
  )
 +
),
 +
INFO(`Продолжаем выполнение...`)
 +
 
 +
Будут выведены следующие сообщения:
 +
* "Освободили ресурсы"
 +
* "Не удалось открыть файл C:\0.txt"
 +
и выполнение скрипта будет прервано.
 +
 
 +
<br>
 +
Пример 3.1.<br>Аналогично предыдущему, но с обработкой исключения во вложенном блоке TRY..EXCEPT и, соответственно, продолжением выполнения скрипта.
 +
  '''TRY'''(
 +
  '''TRY'''(
 +
    /*распределяем ресурсы*/
 +
    :var.str:=TStringList.Create(),
 +
    /*попытка прочитать несуществующий файл*/
 +
    :var.str.LoadFromFile(`C:\0.txt`),
 +
    '''EXCEPT'''(
 +
      /*обрабатываем исключение*/
 +
      INFO(`Не удалось прочитать файл`)
 +
    )
 +
  ),
 +
  '''FINALLY'''(
 +
    /*ВСЕГДА освобождаем ресурсы*/
 +
    :var.str.Free(),
 +
    INFO(`Освободили ресурсы`)
 +
   )
 +
),
 +
INFO(`Продолжаем выполнение...`)
 +
 
 +
Будут выведены следующие сообщения:
 +
* "Не удалось прочитать файл"
 +
* "Освободили ресурсы"
 +
* "Продолжаем выполнение..."
 +
и выполнение скрипта будет продолжено.
 +
 
 +
<br>
 +
Пример 4.
 +
 
 +
Можно использовать объект '''E''' для работы с ошибками:
 +
 
 +
:SDt:=`aaa`,
 +
  '''TRY'''(
 +
  STRTODATE(:SDt),
 +
  '''EXCEPT'''(
 +
    INFO(
 +
      `Произошла какая-то ошибка... Определим её тип.`
 +
      + \
 +
      + `Класс ошибки: `
 +
      + '''E.ClassName()'''
 +
      + \
 +
      + `Текст ошибки: `
 +
      + '''E.Message()'''
 +
    )
 +
  )
 +
),
 +
INFO(`Продолжаем выполнение...`)
 +
 
 +
Будут выведены следующие сообщения:
 +
* Произошла какая-то ошибка... Определим её тип.
 +
:Класс ошибки: EConvertError
 +
:Текст ошибки: 'aaa' is not a valid date and time
 +
:в выражении
 +
:STRTODATE(:SDt)
 +
* Продолжаем выполнение...
 +
 
 +
<br>
 +
Пример 5.
 +
Использование Exit в блоке Finally:
 +
:var.Res:=
 +
'''Try'''(
 +
  aaa,
 +
'''Finally'''(
 +
  '''Exit'''(`Выходим из Finally, а ошибки нет!`)
 +
  )
 +
),
 +
'''Info'''(:var.Res)
  
 +
Вместо ошибки при обращении к неопределённому полю "aaa", будет выведено сообщение:
 +
* Выходим из Finally, а ошибки нет!
 +
Связано это с тем, что функция Exit() в ГБ реализована также через исключения, потому ошибка при обращении к полю теряется. Следует избегать использования конструкций, аналогичных  вышеприведённой.
 
}}
 
}}

Текущая версия на 12:20, 20 мая 2022

Функции для обработки исключений (доступны с версии 1.9.0.9).

Синтаксис

TRY(выражение, выражение, ..., FINALLY(выражение, выражение, ...) )
или
TRY(выражение, выражение, ..., EXCEPT(выражение, выражение, ...) )
или
TRY(выражение, выражение, ..., EXCEPT(выражение, выражение, ..., RAISE() ) )

Аргументы

блок TRY
в блоке TRY находятся выражения, выполнение которых нужно проконтролировать
блок FINALLY
в блоке FINALLY находятся выражения, которые нужно выполнить независимо от того, возникло или нет исключение при выполнении блока TRY. Обычно используется для гарантированного освобождения ресурсов, выделенных в блоке TRY.
Фактически FINALLY не обрабатывает исключение, т.е. скрипт будет прерван, если нет никаких обработчиков EXCEPT. Чтобы всё-таки обработать исключение, нужно использовать вложенные конструкции TRY:
TRY(
  TRY(
    ...,
    EXCEPT(
      ...
    )
  ),
  FINALLY(
    ...
  )
)
блок EXCEPT
в блоке EXCEPT находятся выражения, которые будут выполнены только в том случае, если в блоке TRY возникнет исключение. При этом исключение считается обработанным и выполнение скрипта не прерывается стандартным сообщением об ошибке
RAISE()
функция RAISE(), помещённая в блок EXCEPT, возобновляет исключение, проталкивая его во внешний обработчик или, если такового нет - в стандартный обработчик исключений
Объект E
E - объект для работы с ошибками. Например: E.ClassName(), E.Message(), E.DbMessage().
E.DbMessage() содержит оригинальное сообщение из процедуры, если ошибка была при вызове процедуры, либо то же самое что E.Message() во всех остальных случаях

Тип результата

Нет

Примеры

Пример 1.

:SDt:=`aaa`,
TRY(STRTODATE(:SDt),
    EXCEPT(
        INFO(`Ошибка преобразования даты`)
    )
),
INFO(`Продолжаем выполнение...`)

Будут выведены следующие сообщения:

  • "Ошибка преобразования даты"
  • "Продолжаем выполнение..."

и выполнение скрипта будет продолжено.


Пример 2.

:SDt:=`aaa`,
TRY(STRTODATE(:SDt),
  EXCEPT(
    INFO(`Ошибка преобразования даты`),
    RAISE()
  )
),
INFO(`Продолжаем выполнение...`)

Будут выведены следующие сообщения:

  • "Ошибка преобразования даты"
  • "'aaa' is not a valid date and time"

и выполнение скрипта будет прервано.


Пример 3.

TRY(
  /*распределяем ресурсы*/
  :var.str:=TStringList.Create(),
  /*попытка прочитать несуществующий файл*/
  :var.str.LoadFromFile(`C:\0.txt`),
  FINALLY(
    /*ВСЕГДА освобождаем ресурсы*/
    :var.str.Free(),
    INFO(`Освободили ресурсы`)
  )
),
INFO(`Продолжаем выполнение...`)

Будут выведены следующие сообщения:

  • "Освободили ресурсы"
  • "Не удалось открыть файл C:\0.txt"

и выполнение скрипта будет прервано.


Пример 3.1.
Аналогично предыдущему, но с обработкой исключения во вложенном блоке TRY..EXCEPT и, соответственно, продолжением выполнения скрипта.

TRY(
  TRY(
    /*распределяем ресурсы*/
    :var.str:=TStringList.Create(),
    /*попытка прочитать несуществующий файл*/
    :var.str.LoadFromFile(`C:\0.txt`),
    EXCEPT(
      /*обрабатываем исключение*/
      INFO(`Не удалось прочитать файл`)
    )
  ),
  FINALLY(
    /*ВСЕГДА освобождаем ресурсы*/
    :var.str.Free(),
    INFO(`Освободили ресурсы`)
  )
),
INFO(`Продолжаем выполнение...`)

Будут выведены следующие сообщения:

  • "Не удалось прочитать файл"
  • "Освободили ресурсы"
  • "Продолжаем выполнение..."

и выполнение скрипта будет продолжено.


Пример 4.

Можно использовать объект E для работы с ошибками:

:SDt:=`aaa`,
TRY(
  STRTODATE(:SDt),
  EXCEPT(
    INFO(
      `Произошла какая-то ошибка... Определим её тип.`
      + \
      + `Класс ошибки: `
      + E.ClassName()
      + \
      + `Текст ошибки: `
      + E.Message()
    )
  )
),
INFO(`Продолжаем выполнение...`)

Будут выведены следующие сообщения:

  • Произошла какая-то ошибка... Определим её тип.
Класс ошибки: EConvertError
Текст ошибки: 'aaa' is not a valid date and time
в выражении
STRTODATE(:SDt)
  • Продолжаем выполнение...


Пример 5. Использование Exit в блоке Finally:

:var.Res:=
Try(
  aaa,
Finally(
  Exit(`Выходим из Finally, а ошибки нет!`)
 )
),
Info(:var.Res)

Вместо ошибки при обращении к неопределённому полю "aaa", будет выведено сообщение:

  • Выходим из Finally, а ошибки нет!

Связано это с тем, что функция Exit() в ГБ реализована также через исключения, потому ошибка при обращении к полю теряется. Следует избегать использования конструкций, аналогичных вышеприведённой.