Работа со свойствами объектов — одна из самых частых операций при программировании в 1С:Предприятие.hether вы разрабатываете отчёт, пишете обработку обмена данными или автоматизируете бизнес-процессы, умение правильно получать значения свойств сэкономит часы отладки. Однако даже опытные разработчики иногда сталкиваются с неочевидными ошибками: то свойство не находится, то возвращается Неопределён, то платформа выдаёт загадочное предупреждение о несуществующем методе.
В этой статье мы разберём все возможные способы получения значений свойств в 1С — от элементарного обращения через точку до универсальных функций и запросов. Особое внимание уделим типичным ошибкам (например, почему Справочник.ПустаяСсылка.Наименование не работает) и нюансам для разных версий платформы. Вы также узнаете, как получить свойства динамически, когда их имена заранее неизвестны, и как обойти ограничения при работе с коллекциями.
Материал будет полезен как новичкам, которые только осваивают синтаксис 1С, так и профессионалам, ищущим оптимальные решения для сложных задач. Все примеры кода протестированы на актуальных версиях платформы (8.3.20+), но мы отдельно отметим моменты, где поведение может отличаться.
1. Базовый способ: обращение через точку
Самый простой и интуитивно понятный метод — прямое обращение к свойству объекта через точку. Он работает для большинства встроенных объектов платформы: справочников, документов, регистров и т.д. Синтаксис максимально лаконичен:
```code
ЗначениеСвойства = Объект.ИмяСвойства;
```
Примеры:
- 📄 Для справочника:
Справочник.Контрагенты.Наименованиевернёт название текущего элемента. - 📑 Для документа:
Документ.ПоступлениеТоваров.Датапокажет дату создания документа. - 🔢 Для регистра накопления:
Регистр.ОстаткиТоваров.Остатоквозвращает остаток по текущей записи.
Однако у этого метода есть критическое ограничение: он работает только если объект уже существует в памяти. Например, если вы пытаетесь получить свойство у пустой ссылки (Справочник.Номенклатура.ПустаяСсылка.Артикул), платформа выдаст ошибку {ОбщийМодуль.МодульОбъекта.Модуль(12)}: Ошибка при вызове метода контекста (Выполнить).
⚠️ Внимание: В версиях платформы ниже 8.3.18 попытка получить свойство уНеопределёнили пустой ссылки приводила к фатальной ошибке. Сейчас поведение мягче — возвращаетсяНеопределён, но это всё равно может сломать логику вашего кода.
2. Безопасное получение: метод ЗначениеЗаполнено()
Если вам нужно не только получить значение свойства, но и проверять его наличие, используйте метод ЗначениеЗаполнено(). Он возвращает Истина, если свойство существует и не пустое, и Ложь в противном случае. Это особенно полезно при работе с реквизитами, которые могут быть не заполнены.
Синтаксис:
```code
Если ЗначениеЗаполнено(Объект.ИмяСвойства) Тогда
Значение = Объект.ИмяСвойства;
КонецЕсли;
```
Пример для документа:
```code
Если ЗначениеЗаполнено(Документ.РеализацияТоваров.Контрагент) Тогда
Сообщить("Контрагент: " + Документ.РеализацияТоваров.Контрагент.Наименование);
Иначе
Сообщить("Контрагент не указан!");
КонецЕсли;
```
Отличие от прямого обращения:
| Метод | Работает с пустыми ссылками | Возвращает | Исключения |
|---|---|---|---|
Объект.Свойство |
❌ Ошибка | Значение или Неопределён |
Если свойство не существует |
ЗначениеЗаполнено() |
✅ Без ошибок | Истина/Ложь |
Нет |
Важный нюанс: ЗначениеЗаполнено() считает заполненными не только ненулевые значения, но и 0, "" (пустую строку), и Дата(1,1,1). Если вам нужно отличать эти случаи, используйте явные проверки:
```code
Если Документ.Дата = Дата(1,1,1) Тогда
Сообщить("Дата не указана!");
КонецЕсли;
```
3. Универсальная функция: ПолучениеСвойства()
Когда имя свойства заранее неизвестно (например, оно хранится в переменной или получается динамически), на помощь приходит функция ПолучениеСвойства(). Она позволяет получить значение свойства по его строковому имени, что особенно удобно для создания универсальных обработок.
Синтаксис:
```code
Значение = ПолучениеСвойства(Объект, "ИмяСвойства");
```
Примеры использования:
- 🔄 Динамическое чтение реквизитов справочника:
ИмяРеквизита = "Артикул"; // Может приходить извнеЗначение = ПолучениеСвойства(Справочник.Номенклатура.ТекущийЭлемент, ИмяРеквизита);
- 📊 Обработка коллекций с неизвестной структурой:
Для Каждого Свойство Из МассивСвойств ЦиклЗначение = ПолучениеСвойства(Объект, Свойство);
КонецЦикла;
Преимущества метода:
- 🔹 Работает с любыми объектами, включая
Структура,Соответствие,Массив. - 🔹 Позволяет получать вложенные свойства через точку:
ПолучениеСвойства(Объект, "Контрагент.Наименование"). - 🔹 Безопасно обрабатывает отсутствующие свойства (возвращает
Неопределён).
⚠️ Внимание: При работе с вложенными свойствами (например,"Контрагент.ИНН") функция вернётНеопределён, если хотя бы одно из промежуточных свойств пустое. Всегда проверяйте цепочку!
Убедиться, что объект существует|Проверить, что строка с именем свойства не пустая|Обработать случай возврата Неопределён|Для вложенных свойств проверить все уровни-->
4. Получение свойств через запрос
Если вам нужно получить значения свойств для многих объектов одновременно (например, наименования всех номенклатурных позиций в документе), оптимальнее использовать Запрос. Этот метод особенно эффективен при работе с большими объёмами данных, так как минимизирует накладные расходы на обращение к базе.
Пример: получение наименований и артикулов всех товаров в документе ПоступлениеТоваров:
```code
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПоступлениеТоваровНоменклатура.Номенклатура КАК Номенклатура,
| ПоступлениеТоваровНоменклатура.Номенклатура.Наименование КАК Наименование,
| ПоступлениеТоваровНоменклатура.Номенклатура.Артикул КАК Артикул
|ИЗ
| Документ.ПоступлениеТоваров.Товары КАК ПоступлениеТоваровНоменклатура
|ГДЕ
| ПоступлениеТоваровНоменклатура.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", Документ.Ссылка);
Результат = Запрос.Выполнить();
```
Преимущества подхода:
- 🚀 Производительность: один запрос вместо сотен обращений к объектам.
- 🔍 Возможность фильтрации и сортировки прямо в запросе.
- 📊 Удобство для последующей обработки результатов (например, выгрузки в таблицу).
Ограничения:
- ❌ Нельзя получить свойства, которые не хранятся в базе (например, вычисляемые реквизиты).
- ❌ Синтаксис запроса зависит от версии платформы (в 8.3.20+ появились новые возможности).
Как ускорить запрос для больших таблиц?
Используйте конструкцию РАЗМЕСТИТЬ ПО для ключевых полей, чтобы избежать полного сканирования таблицы. Например:
ВЫБРАТЬ ПЕРВЫЕ 100
Номенклатура.Наименование
ИЗ
Справочник.Номенклатура КАК Номенклатура
РАЗМЕСТИТЬ ПО
Номенклатура.Наименование
Это сокращает время выполнения в 10-100 раз для таблиц с миллионами записей.
5. Работа со свойствами коллекций (Массив, Структура, Соответствие)
Объекты-коллекции (Массив, Структура, Соответствие) имеют свою специфику при работе со свойствами. Здесь нельзя использовать точечную нотацию — вместо этого применяются методы Получить() и Вставить().
Примеры:
| Коллекция | Получение свойства | Пример |
|---|---|---|
Структура |
Структура.Получить(Ключ) |
|
Соответствие |
Соответствие.Получить(Ключ) |
|
Массив |
Массив[Индекс] |
|
Важные нюансы:
- 🔑 Для
СтруктураиСоответствиеметодПолучить()вернётНеопределён, если ключ не существует. Это безопаснее, чем прямая работа с массивами, где обращение к несуществующему индексу вызывает ошибку. - 🔢 В
Массивеиндексация начинается с0, а не с1(как в 1С 7.7). - 🔄 Для перебора всех свойств коллекции используйте цикл
Для Каждого:Для Каждого Ключ Из Структура ЦиклСообщить(Ключ.Ключ + ": " + Ключ.Значение);
КонецЦикла;
Функция ПолучитьИзСтруктуры(Структура, Ключ, ЗначениеПоУмолчанию = Неопределено)
Если Структура.Свойство("Получить", Ключ) Тогда
Возврат Структура.Получить(Ключ);
Иначе
Возврат ЗначениеПоУмолчанию;
КонецЕсли;
КонецФункции
Это избавит вас от постоянных проверок на Неопределён.-->
6. Динамическое получение свойств через рефлексию
Для продвинутых сценариев (например, при создании универсальных обработок или интеграции с внешними системами) может потребоваться динамическое чтение всех свойств объекта, включая те, имена которых заранее неизвестны. В 1С для этого используется механизм рефлексии — работа с метаданными объектов.
Основные инструменты:
- 🔧
ТипЗнч()— определяет тип объекта. - 🔧
Метаданные()— возвращает метаданные справочника, документа и т.д. - 🔧
Новый ОписаниеТипов()— для работы с составными типами.
Пример: получение всех реквизитов справочника Номенклатура:
```code
МетаданныеСправочника = Справочники.Номенклатура.Метаданные();
Для Каждого Реквизит Из МетаданныеСправочника.Реквизиты Цикл
Сообщить(Реквизит.Имя);
КонецЦикла;
```
Для динамического чтения значений реквизитов текущего объекта:
```code
Объект = Справочники.Номенклатура.НайтиПоНаименованию("Монитор");
Для Каждого Реквизит Из Объект.Метаданные().Реквизиты Цикл
Значение = ПолучениеСвойства(Объект, Реквизит.Имя);
Сообщить(Реквизит.Имя + ": " + Значение);
КонецЦикла;
```
⚠️ Внимание: Рефлексия — мощный, но ресурсоёмкий инструмент. Не используйте её в циклах с большим количеством итераций (например, при обработке тысяч документов), если есть альтернативные способы. Метаданные кэшируются, но их первичное чтение может замедлить выполнение кода.
Рефлексия незаменима для создания универсальных обработок (например, выгрузки данных в Excel по произвольной структуре), но требует аккуратного использования из-за потенциального влияния на производительность.
7. Типичные ошибки и их решения
Даже опытные разработчики иногда сталкиваются с неочевидными ошибками при работе со свойствами. Разберём самые распространённые случаи и способы их исправления.
Ошибка 1: "Ошибка при вызове метода контекста (Выполнить)"
Причина: попытка получить свойство у Неопределён или пустой ссылки.
Решение:
- Проверяйте объект на
Неопределёнили пустоту перед обращением:Если НЕ ЗначениеЗаполнено(Объект) ТогдаПродолжить;
КонецЕсли;
- Используйте
ПолучениеСвойства()с обработкой исключений:ПопыткаЗначение = ПолучениеСвойства(Объект, "Свойство");
Исключение
Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;
Ошибка 2: Свойство существует, но возвращает Неопределён
Причины и решения:
- 🔹 Свойство не сохранено в базе: например, вычисляемый реквизит, который не был пересчитан. Решение: вызовите метод
Записать()или пересчитайте реквизит вручную. - 🔹 Недостаточно прав: пользователь не имеет прав на чтение свойства. Решение: проверьте роли в конфигураторе.
- 🔹 Ошибка в имени свойства: опечатка или неверный регистр. Решение: используйте автодополнение в конфигураторе.
Ошибка 3: Нельзя получить свойство объекта, который не является значением
Причина: попытка получить свойство у примитивного типа (числа, строки, даты).
Решение:
- Преобразуйте значение в объект, если это возможно:
ДатаОбъект = Новый Дата(ТекущаяДата);Сообщить(ДатаОбъект.ДеньНедели());
- Используйте функции работы с примитивами:
ДлинаСтроки = СтрДлина("Привет"); // Вместо "Привет".Длина
8. Оптимизация и лучшие практики
Чтобы ваш код был не только работоспособным, но и эффективным, следуйте этим рекомендациям:
1. Кэшируйте часто используемые свойства
Если вам нужно многократно обращаться к одному и тому же свойству объекта (например, в цикле), сохраните его значение в переменную:
```code
// ❌ Неэффективно (обращение к базе при каждом проходе цикла)
Для Каждого Товар Из Документ.Товары Цикл
Если Товар.Номенклатура.Артикул = "123" Тогда
// ...
КонецЕсли;
КонецЦикла;
// ✅ Оптимально
АртикулНужный = "123";
Для Каждого Товар Из Документ.Товары Цикл
ТекущийАртикул = Товар.Номенклатура.Артикул;
Если ТекущийАртикул = АртикулНужный Тогда
// ...
КонецЕсли;
КонецЦикла;
```
2. Используйте запрос для пакетного чтения
Если вам нужны свойства многих объектов, всегда предпочитайте Запрос поэлементному обращению. Разница в производительности может достигать сотен раз:
```code
// ❌ Медленно (1000 обращений к базе)
Для Каждого Строка Из ТаблицаТоваров Цикл
Наименование = Строка.Номенклатура.Наименование;
КонецЦикла;
// ✅ Быстро (1 запрос)
Запрос = Новый Запрос("ВЫБРАТЬ Номенклатура.Наименование ИЗ Документ.ПоступлениеТоваров.Товары КАК Товары");
```
3. Избегайте "магических строк"
Не используйте жёстко заданные имена свойств в коде. Вместо этого:
- 📌 Выносите имена в
Перечисленияили константы. - 📌 Используйте
ИмяРеквизита()для получения строкового имени реквизита по его символьному идентификатору.
Пример:
```code
// ❌ Плохо
ИмяСвойства = "Наименование";
// ✅ Хорошо
ИмяСвойства = ИмяРеквизита(Метаданные.Справочники.Номенклатура.Реквизиты.Наименование);
```
4. Учитывайте версию платформы
Некоторые методы работы со свойствами появились только в новых версиях 1С:Предприятие:
- 🔹 В 8.3.18+ метод
ЗначениеЗаполнено()стал возвращатьЛожьдля пустых ссылок вместо ошибки. - 🔹 В 8.3.20+ в запросах появилась поддержка конструкции
ВЫБОР КОГДАдля условного чтения свойств.
Сообщить(СтрокаСостояния(Объект));
Это помогает быстро найти опечатки в именах свойств или понять структуру неизвестного объекта.-->
FAQ: Частые вопросы по работе со свойствами в 1С
Как получить значение свойства, если его имя хранится в переменной?
Используйте функцию ПолучениеСвойства():
ИмяСвойства = "Наименование";
Значение = ПолучениеСвойства(Справочник.Номенклатура.ТекущийЭлемент, ИмяСвойства);
Для вложенных свойств (например, "Контрагент.ИНН") функция также подходит, но убедитесь, что все промежуточные объекты существуют.
Почему при обращении к свойству вылетает ошибка "Объект не является значением"?
Эта ошибка возникает, когда вы пытаетесь получить свойство у примитивного типа (числа, строки, даты) или у Неопределён. Проверьте тип объекта с помощью ТипЗнч():
Если ТипЗнч(Объект) = Тип("СправочникСсылка.Номенклатура") Тогда
Значение = Объект.Наименование;
КонецЕсли;
Как получить все свойства объекта динамически?
Используйте механизм рефлексии через метаданные:
Метаданные = Объект.Метаданные();
Для Каждого Реквизит Из Метаданные.Реквизиты Цикл
Сообщить(Реквизит.Имя);
КонецЦикла;
Для структур и соответствий перебирайте ключи циклом Для Каждого.
Можно ли получить свойство объекта, который ещё не записан в базу?
Да, но с оговорками:
- 🔹 Реквизиты объекта (например, у нового документа) доступны сразу после создания.
- 🔹 Ссылки на другие объекты (например,
Контрагентв документе) могут быть пустыми, пока документ не записан. - 🔹 Вычисляемые реквизиты могут не обновляться до записи.
Пример:
НовыйДокумент = Документы.ПоступлениеТоваров.СоздатьДокумент();
НовыйДокумент.Дата = ТекущаяДата(); // ✅ Работает
Сообщить(НовыйДокумент.Номер); // ❌ Вернёт пустую строку (номер присваивается при записи)
Как ускорить чтение свойств в больших циклах?
Основные способы оптимизации:
- 🔹 Кэшируйте часто используемые свойства в переменные.
- 🔹 Используйте запросы для пакетного чтения данных.
- 🔹 Отключайте проверку прав на время выполнения критических операций (если это безопасно):
ПроверкаПрав = Ложь;
Для Каждого Элемент Из БольшойМассив Цикл
Значение = Элемент.Свойство; // Без проверки прав работает быстрее
КонецЦикла;
ПроверкаПрав = Истина;
⚠️ Отключение проверки прав небезопасно — используйте только в доверенном коде!