Всем привет! Сегодня разберём довольно простую тему, которую я, несмотря на всю её простоту, полностью понял только через полгода самостоятельного обучения программированию.
Дисклеймер: описанные в статье вещи могут быть супер-понятны всем программистам и тем, кто учится на курсах программирования, но могут быть неочевидны тем, кто занимается проектированием и учиться программировать — а это, как мне кажется, основная аудитория моего блога.
Введение
Для объяснения разницы рассмотрим пример из Revit: параметры типа и экземпляра. В чём разница?
- Параметр типа касается всех-всех экземпляров данного типа. При его изменении у типа его значение изменится у всех экземпляров.
- Параметр экземпляра касается конкретного экземпляра, и его изменение не влияет на другие экземпляры данного типа.
- Параметр типа существует в проекте и может быть изменён, даже если в проекте не размещено экземпляров. Параметр экземпляра, соответственно, существует только у размещённого экземпляра.
Например, если мы создадим 3 стены одного типа, и поменяем им толщину через "Изменить тип", то толщина изменится у всех стен. Для её изменения, в общем, создавать стены необязательно. Если мы изменим высоту стены, то она изменится только у конкретной стены. Да и пока мы её не создадим, поменять мы её не сможем.
Что же мы имеем в программировании?
У классов есть поля, свойства и методы. Они могут быть статическими и нестатическими (экземплярными). С нестатическими членами классов всё понятно: создали экземпляр и работаем с ним, а пока не создали, использовать их не можем. Почти один в один экземпляры семейств в Revit.
Статические свойства и методы немного отличаются от параметров типа. Основная разница в том, что в Revit типоразмер — это только типоразмер, а классом может быть и типоразмер, и категория, и весь документ, да и вообще всё что угодно. А дальше принцип такой же:
- Мы не создаём экземпляр, чтобы использовать статические члены, а обращаемся непосредственно к имени класса.
- Если у нас есть статическое свойство и несколько экземпляров, то, поменяв его значение, обратившись к классу через имя класса, мы изменим и все его экземпляры.
Примеры из Revit API
Чтобы определить, является ли член класса или класс статическим, просто смотрим в документацию. У статических классов будет слово static перед его объявлением. У статического члена класса будет то же слово static перед его объявлением.
Экземпляр статического класса создать нельзя. Например, класс Math. Мы можем использовать его методы (округление, синус, косинус и т.д, или свойства (PI), но создавать его нам для этого не нужно — ведь эти правила и константы всегда работают одинаково).
Как этим пользоваться?
Допустим, нам надо получить Категорию для каких-либо действий. Мы идём в класс Category и находим метод GetCategory. Допустим, мы не знаем разницы между статическими и нестатическими методами. И получаем абсурд: чтобы получить категорию, нужно иметь категорию, но где её взять. Самое главное, что когда мы написали код, он не компилируется:
Я специально обвёл подсказку красным. Всё просто: вместо переменной используем имя класса:
Теперь всё работает: мы получили категорию.
По похожему принципу работают, например, методы, создающие элементы: Wall.Create, Duct.Create и т.д., а также почти все классы с Utils в названии.
Лайфхак: если вам что-то нужно сделать с элементом, а подходящего метода в API нет, то посмотрите, может быть есть соответствующий класс Utils? Например, разделить части можно через PartUtils, а через Part — нет.
Сохранение данных между запусками плагина
Я не рекомендую использовать этот способ, так как он приводит к багам и перегружает память, но расскажу о нём в качестве иллюстрации, и чтобы вы не применяли static свойства там, где их лучше не применять
Static свойства и поля существуют вне зависимости от того, существуют ли экземпляры класса. С их помощью можно простейшим образом сохранять настройки между запусками плагина.
Допустим, у нас плагин с пользовательским вводом. Было бы удобно, если пользователь не вводил бы данные каждый раз, а они бы восстанавливались после предыдущего запуска.
По-хорошему, такую задачу надо решать, сохраняя настройки в json или xml файле. Тогда они и хранится будут между проектами, и между запусками Ревита. Но внутри одного запуска можно решить чуть проще: объявить заполняемые пользователем поля статическими.
Такой финт не сработает с addin-manager-ом, надо именно добавлять плагины на ленту Revit.
А в чём проблемы такого подхода:
- Можно случайно объявить не те переменные static, и потом, допустим, у вас при исполнении плагина список будет разрастаться, а не обновляться. И будет странное поведение: отладка проходит хорошо (через addin-manager), первые 3 запуска всё ок, а потом — не работает.
- Статические свойства не стираются из памяти после выполнения команды, и, если перегрузить их, можно получить замедление работы при незапущенных плагинах.
На сегодня всё. Напоминаю, что у меня есть подборка статей про основы C#, а также телеграм-канал о Revit API. Обязательно подписывайтесь и ставьте лайки. До новых встреч!