Найти тему

Основы С#. Конструкция try-catch и возможности её применения в Revit API

Оглавление

Всем привет! Сегодня вновь вернёмся к базовым функциям языка C#, но не забудем и про Revit API: в конце вас ждёт интересный код.

Конструкция try-catch-finally позволяет обрабатывать исключения и делать с ними определённые действия. Но давайте сначала разберёмся, что такое исключения и зачем вообще они нужны.

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

Рассмотрим пример. Напишем код в консольном приложении:

int i = 5;
int j = 0;
i= i / j;

Запустим:

Деление на ноль
Деление на ноль

Иногда возникшие случаи бывают сложнее. Например, если написать в классе свойство, ссылающееся на само себя при попытке получения, а затем вызвать его в коде:

-2

Получим переполнение стека и потенциальные ошибки:

-3

Если написать такое в плагине для Revit, то Revit завершится с фатальной ошибкой (можете проверить).

Конструкция try-catch-finally предназначена для перехвата ошибок и их обработки. Рассмотрим синтаксис:

-4

Сначала идёт обязательный блок try. В нём выполняются все инструкции. Если возникло исключение, то выполнение прекращается, и исполняются инструкции блока catch. Если исключение не возникло, то блок catch не выполняется. Блок finally выполняется сразу после этих 2 блоков в любом случае.

Любой из блоков может быть пустым, блок catch можно не писать, а сразу написать finally, но совсем без них нельзя.

Где это можно применять в Revit API

Можно (но не обязательно нужно) применять где угодно: захотели, весь код обернули в try-catch (для отладки), захотели — проверили так наличие параметра. Но я настоятельно так делать не советую.

NullReferenceException

Чаще всего вы будете сталкиваться именно с таким исключением. Когда оно может возникнуть:

  • Вы берёте значения параметра, который не найден, и вернул null.
  • Вы берёте свойство элемента у свойства, которое вернуло null.
  • Вы пытаетесь добавить элемент в список, который не был проинициализирован пустым списком.
List<int> ints = new List<int>(); — инициализировали.
List<int> ints; — не инициализировали.
  • Когда угодно.

Бороться с ним лучше всего не конструкцией try-catch, а проверкой на null:

Проверяем параметр на null
Проверяем параметр на null

Где нужно применять конструкцию try-catch и это будет уместно и правильно

  • Как было сказано выше, при отладке.
  • При работе с файлами (тут часто бывают исключения: файл может быть недоступен, не существовать, и т.д).
  • При работе со сторонним API (отправка данных на сервер и чтение с сервера, запись в Excel и другие варианты).
  • При использовании метода PickObject(ObjectType.Element);

(вообще неприятный метод, человек жмёт Esc и вылезает противное сообщение об ошибке, никому не нужное. Нужно просто прервать работу и всё).

  • И в других случаях, которых вы посчитаете это оправданным (список может быть не полным — пишите свои варианты в комментарии).

А теперь — обещанный интересный код

Я начинал свою карьеру в строительной отрасли проектировщиком систем противопожарной защиты. Существуют адресные системы пожарной сигнализации: такие системы, где каждый извещатель имеет свой адрес (номер). При срабатывании на экране диспетчера отобразится место возгорания с точностью до помещения и 5-10 м в большом помещении. Удобно

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

Встречайте: метод полуавтоматической нумерации в порядке прощёлкивания.

-6

Просто поменяйте ваш префикс, ваше имя параметра и начальное значение в строках 194-195.

Код будет выполняться до тех пор, пока у выбираемых пользователем элементов есть этот параметр, и пока он/она не нажмёт Esc — за это отвечает цикл while. Более того, если элементы будут замаркированы на виде, где выполняется плагин, и в марки будет выведен выбранный параметр, то значения марок будут изменяться прямо на ходу (потому что мы каждый элемент обрабатываем в отдельной транзакции.
4 года назад такой плагин сэкономил бы мне уйму времени. Правда, тогда я бы не смог его установить, не зная статьи по
созданию и подключению плагина. Впрочем, точно такой же код можно забить себе и в макросе.

Итоговый код в моём репозитории на GitHub

А на этом всё. Подписывайтесь на мой телеграм-канал, пишите комментарии. До новых встреч!

-7