Методическая рекомендация
При изучении возможностей типизации следует учитывать, что:
1С:Стандарты разработки V8
добавляет только контроль типов в 1C:EDT и проблемных ситуаций на основе базовых возможностей 1C:EDTДинамический расчет типов, выполняемый в 1С:EDT на основе контекста 1С:Предприятия и метаданных конфигурации.
Система типизации кода 1C:EDT отслеживает тип переменных в зависимости от их использования (местоположения в коде)
МояПеременная = 10;
...
Если МояПеременная > 0 Тогда // В этом месте тип - Число
КонецЕсли;
...
МояПеременная = Истина;
...
Если МояПеременная Тогда // В этом месте тип - Булево
КонецЕсли;
При анализе объектов данных (Data-flow analysis), создаваемых программно, система типизации 1C:EDT учитывает только те типы, которые были указаны в момент инициализации свойства в объекте данных.
Параметры = Новый Структура("МоеСвойство"); // Инициализация без указания начального типа
...
Параметры.МоеСвойство = 10; // Смена типа с Неопределено на Число не происходит
...
Если Параметры.МоеСвойство > 0 Тогда // В этом месте тип МоеСвойство - Неопределено
КонецЕсли;
...
Параметры.Вставить("ДругоеСвойство", Ложь); // Свойство инициализируется с начальным значением
Параметры.ДругоеСвойство = 1; // Смена типа не происходит
...
Если Параметры.ДругоеСвойство Тогда // В этом месте тип свойства - Булево
КонецЕсли;
...
Если ТипЗнч(Параметры.ДругоеСвойство) = Тип("Число") Тогда
Параметры.ДругоеСвойство = Параметры.ДругоеСвойство + 1; // В этом месте тип свойства - Булево
КонецЕсли;
При фактической смене типа значения у свойства объекта, который допускает такое поведение в run-time 1С:Предприятия 8
, система типизации и анализа объектов данных в 1C:EDT не учитывает эту смену.
В этом случае, правильным подходом является: указание начального типизированного значения, и не допускать изменения типа значения далее в коде. Т.е., фактически - есть два варианта у переменных: 1. Тип определен пользователем явно, и дальше он меняться не будет, а попытку изменения - можно будет отслеживать. 2. Если тип неопределен явно, то он ВСЕГДА будет неопределен и далее, и плагин будет во всех местах его считать именно неопределенным. Фактически - данный подход запрещает использовать конструкцию Перем
без явного указания типа в комментарии.
Статическое указание типов в документирующих/типизирующих комментариях, ссылки на функции-конструкторы и ссылки на входящие параметры других методов.
Существуют стандартные инструменты в 1C:EDT и добавляемые расширениями (плагинами) инструменты, которые помогают типизировать код.
Документация по Контекстной подсказке
F2
для отображения описания объекта - перед именем объекта должен отображаться его тип.ПолеВвода
, а в контекстной подсказке у вас показываются методы других типов, например, ГруппаФормы
, то это значит, что EDT нашла места вызова этой функции, в которых передается другой тип. И это убрать или переопределить типы - нельзя на текущий момент.Внимание! Контекстный помощник ввода работает при наборе документирующих комментариев.
Диагностика проблемы:
Ctrl+Space
) - подсказка ввода не показывает свойства в формате Объект.Свойство <Тип свойства> ~ Тип объекта
Обратите внимание! В подсказке ввода - после имени свойства указан тип свойства
<Тип свойства>
в фигурных скобках и после~ Тип объекта
- тип, из которого это свойство получено, т.к. у объекта может несколько типов.
Чтобы найти причины не типзированного кода, можно следовать некоторым пунктам:
F2
для вывода подсказкиF3
и в месте определения выяснить типУправляемаФорма
, ТаблицаЗначений
, Массив
, Структура
, ДокументОбъект
, СправочникСсылка
и т.д. без спецификации каких либо конкретных свойств к которым необходимо обращатьсяДокументация по Генератору документирующего описания методов
Документация по панели структуры документирующего комментария
Позволяет увидеть структуру данных документирующего комментария так как её считывает 1C:EDT, увидеть расхождения с тем что ожидал разработчик и тем что он написал.
Кратко: это контроль (валидация) наличия всех типов, как декларативных, так и динамически-рассчитанных, в коде 1С:Предприятия 8
. Этот контроль предоставляется расширением "1С:Стандарты разработки V8" для 1С:EDT.
Ключевые возможности:
1С:Предприятия 8
- только контролируется существющие типыУ многих разработчиков 1С
возникает справедливая ассоциация с языком TypeScript
. При разработке "Строгой типизации" мы действительно "подглядывали" в связку этих двух языков TS + JS
.
Подробнее про TypeScript здесь.
В чем "Строгая типизация 1С" похожа на TypeScript
:
TypeScript
после компиляции исполняется в браузере1С:Предприятия 8
1С:Предприятия 8
смена типа по-прежнему возможнаTypeScript
взаимодействует с модулями JSВ чем отличие "Строгой типизации" от TypeScript
:
1С:Предприятия 8
1С:Предприятия 8
1С:Предприятия 8
присутствует - тут 50/50, не стоит холиварить на эту тему.1С:Предприятия 8
1С:Предприятия 8
При использовании дополнительного расширения "1С:Стандарты разработки" для 1С:EDT рекомендуется для модуля включить строгую типизацию, которая будет контролировать, что все типы были созданы правильно, во всех местах используется жесткие ссылки на объекты-создатели, что нет смены типа у переменной.
Контроль типизации будет выполняться для всего модуля, включая не экспортные методы. Контролируется наличие типов всех переменных, используемых вызовов общих модулей, при обращении к полям/свойствам объектов контролируется их наличие и их типы. Это означает, что для не экспортых методов необходимо писать типизирующие документирующие комментарии для входящих параметров и типы возвращемых значений функций, если код написан не прозрачно для анализа системы типизации 1C:EDT. Написание текстов описаний методов и параметров для других разработчиков - не является обязтельным в контексте типизации кода.
Для включения строгой типизации, необходимо в заголовке модуля указать аннотацию до первого семантического объекта (области, процедуры, переменной):
//@strict-types
#Область ПрограммныйИнтерфейс
...
Далее 1C:EDT будет отображать ошибки, если с объектами и их типами что-то не корректное.
Групповое включение строгой типизации можно выполнить командой Включить строгую типизацию (@strict-types) в модулях
в контекстном меню:
В каких случаях рекомендуется применять:
Стандарт 1С Описание процедур и функций п.2 требует наличие описания только программного интерфейса. Это означает, что:
"ПрограммныйИнтерфейс"
необходимо указывать описание смысла методов и параметров для программиста, так же обязательное указание типовСистема типизации кода в 1C:EDT работает по принципу расширения типов, собирая информацию о типах из всех возможных источников.
МояПеременная = ФункцияРазличныхТипов(Ложь); // Булево - добавляем ещё тип
Функция ФункцияРазличныхТипов(Флаг)
Если Флаг Тогда
Вовзрат Новый Массив;
Иначе
Вовзрат 10;
КонецЕсли;
КонецФункции
В данном примере - EDT сама рассчитает 2 типа - Массив|Число
, и, при помощи коментария - мы расширим тип переменной МояПеременная
до третьего типа - Булево
. Теперь - EDT позволит вам выполнять любые действия над этой перменной, если это действие можно выполнить хотябы над одним типом (рассчитанным EDT, или добавленным вами через типизирующий комментарий).
Если ТипЗнч(МояПеременная) = Тип("СправочникОбъект.Товары") Тогда
МояПеременная.Артикул = "";
МояПеременная.Записать();
при этом внутри условия переменная будет указанного в проверке типа, как в рантайме, так и для статического анализатора. Условие проверки должно быть простым.
Для задачи переопределения расчетных типов на основе кода, которые считает система 1C:EDT, необходимо указать в документирующих комментариях тип входящего параметра.
// @strict-types
...
// Где-то в коде вызыв функции, которая ниже
Ответ = МакетПечати(Документы.Заказ.СоздатьДокумент());
...
// Параметры:
// Док - ДокументОбъект.Заказ - Это строка
//
// Возвращаемое значение:
// ТабличныйДокумент - Тест
&НаСервереБезКонтекста
Функция МакетПечати (Док)
Док.Автор = Справочники.Пользователи.ПустаяСсылка();
Макет = Док.ВернутьМакет();
Возврат Макет;
КонецФункции
Следует учитыать, что для метода система типизации 1C:EDT собирает все локальные вызовы в текущем модуле и анализирует типы передаваемые в вызов - внутри метода тип параметра будет расчетный, но при вызове локальной метода система строгой типизации будет отображать ошибку несоответствия типов:
...
// Здесь ошибка на несоотвествие типов
Ответ = МакетПечати(Документы.РасходТовара.СоздатьДокумент());
...
В этом случае, переменная Док
будет уже иметь два расчетных типа. Например, если у документа РасходТовара
нет реквизита Автор
и нет функции в модуле объекта ВернутьМакет
, то в теле метода никаких ошибок.
Если есть цель выяснить - будут ли проблемы при передачи нового типа в функцию, необходимо код писать безопасно, с проверкой типа параметра:
БЫЛО:
Функция МакетПечати (Док)
Док.Автор = Справочники.Пользователи.ПустаяСсылка();
Макет = Док.ВернутьМакет();
Возврат Макет;
КонецФункции
СТАЛО:
Функция МакетПечати (Док)
Если ТипЗнч(Док) = Тип("ДокументОбъект.Заказ") Тогда
// Тут ошибок не будет, так как у заказа есть все функции и реквизиты
Док.Автор = Справочники.Пользователи.ПустаяСсылка();
Макет = Док.ВернутьМакет();
Если ТипЗнч(Док) = Тип("ДокументОбъект.РасходТовара") Тогда
// В этой ветке следует определить другой алгоримт,
// так как Док будет иметь тип - где нет реквизита и функции:
Док.Автор = Справочники.Пользователи.ПустаяСсылка();
Макет = Док.ВернутьМакет();
КонецЕсли;
Возврат Макет;
КонецФункции
Документирующие комментарии необходимы для 2х целей:
1C:EDT поддерживает решение этих целей независимо друг от друга: можно писать описания без типов, или типы без описаний, или комбинация типов и описаний.
Структуру данных документирующего комментария можно представить в следующем упрощенном иерархическом виде:
Description: # Объект описания, состоящий из коллекции строк и ссылок
- TextPart # Текстовая строка описания
- LinkPart # Ссылка на сайт или на метод конфигурации
ParameterSection: # Секция параметров метода, у секции может быть свою описание
Description:
- ...
ParameterDefinitions: # Список параметров
- FieldDefinition:
Name: ParameterName # Имя параметра
Description: # Описание параметра
- ...
TypeSections: # Список секций типов, может быть несколько
- TypeSection:
Description:
- ...
TypeDefinitions: # Список определений типов
- TypeDefinition:
TypeName: TypeName # Имя тип 1С
ContainTypes: # Список описаний типов элементов коллекций, если в определении указана колекция
- TypeDefinition:
...
- TypeDefinition
FieldDefinitionExtension: # Возможность расширить тип полями (для структур, ТЗ и т.д.)
- FieldDefinition:
...
- TypeDefinition
- LinkContainsTypeDefinition # Определение типа содержащего ссылку на функцию или параметр
LinkPart: LinkPart
- FieldDefinition:
...
CallOptionsSecton: # Секция параметров вызова
Description:
- ...
ExampleSection: # Секция примеров использования метода
Description:
- ...
ReturnSection: # Секция описания возвращаемого значения функции
Description:
- ...
ReturnTypes: # Список секций типов возвращаемых значений
- TypeSection:
Description:
- ...
TypeDefinitions:
- TypeDefinition:
...
- TypeSection:
...
Рассмотрим подробнее на примерах возможности документирующих комментариев.
Описание - многострочное, со ссылками
// В описании рекомендуется писать все ссылки на отдельной строке.
// ссылки на веб-страницы:
// См. https://1c.ru
// Ссылка на функцию в тексте описания
// См. ОбщегоНазначения.ФункцияМодуля
//
Процедура ОбработкаОбъекта(Объект)
В секции параметры, после ключевого слова Параметры
- обязательно идет двоеточие
// Описание метода
//
// Параметры:
// Объект - СправочникОбъект.Товары
Процедура ОбработкаОбъекта(Объект)
Иначе секция параметров - превращается в описание метода
// Здесь все 3 строки являются описанием метода и не содержат декларации параметров
// Параметры
// Объект - СправочникОбъект.Товары
Процедура ОбработкаОбъекта(Объект)
Возможно описание поля/параметра без указания типа, но лучше так не делать
// Описание метода
//
// Параметры:
// У секции параметров может быть своё описание
// Объект - У параметра может быть описание без декларации типов
Процедура ОбработкаОбъекта(Объект)
Обычно, описание поля/параметра идет после секции определения типов
// Параметры:
// Объект - СправочникОбъект.Товары - Здесь описание для типа
Процедура ОбработкаОбъекта(Объект)
Возможно указание описания для каждого типа поля/параметра, когда каждый тип записан с новой строки, через дефис-минус. Не допускается использование различных видов "тире" (длинных, коротких, средних и т.д.)
// Параметры:
// Объект - СправочникОбъект.Товары - Здесь описание для типа
// - ДокументОбъект.РеализацияТоваров - Здесь описание для другого типа
Процедура ОбработкаОбъекта(Объект)
Простой вариант записи нескольких типов - через запятую
// Параметры:
// Объект - СправочникОбъект.Товары, ДокументОбъект.РеализацияТоваров - Здесь описание для списка типов
Процедура ОбработкаОбъекта(Объект)
В простом случае - описание поля/параметра может быть многострочным
// Параметры:
// Объект - СправочникОбъект.Товары - Здесь описание для типа
// Вторая строка описания параметра
Процедура ОбработкаОбъекта(Объект)
Описание единственного типа элементов коллекции
// Параметры:
// Объект - Массив из СправочникОбъект.Товары - Здесь единственный тип элементов
Процедура ОбработкаОбъекта(Объект)
Описание составного типа элементов коллекции через запятую
// Параметры:
// Объект - Массив из СправочникОбъект.Товары, ДокументОбъект.РеализацияТоваров -
Процедура ОбработкаОбъекта(Объект)
Возможность указывать расширение полей для типа, строго после двоеточия в конце однострочного описания
// Параметры:
// Объект - Структура - Здесь нельзя многострочное описание:
// * ПолеСтруктруы - ТаблицаЗначений - Описание поля структуры, после опять раширение уже для таблицы:
// ** ИмяКолонки - Число - описание колонки таблицы
Процедура ОбработкаОбъекта(Объект)
Можно не писать описание, оставлять только типы и обязательное двоеточие
// Параметры:
// Объект - Структура:
// * ПолеСтруктруы - ТаблицаЗначений:
// ** ИмяКолонки - Число
Процедура ОбработкаОбъекта(Объект)
Не всегда возможно правильно определять что сейчас "описание без типа" или "тип без описания", поэтом может требоваться указание дефиса после списка типов для явного опредлеения секции типов
// Параметры:
// Объект - Структура, ТаблицаЗначений -
Процедура ОбработкаОбъекта(Объект)
В этом случае без секция со списком типов превращается в просто текстовое описание
// Возвращаемое значение:
// Структура, ТаблицаЗначений
Функция ОбработкаОбъекта(Объект)
Декларацию списка типов возвращаемого значения нужно записывать явно с дефисом в конце или с новой строки
// Возвращаемое значение:
// Структура, ТаблицаЗначений -
Функция ОбработкаОбъекта(Объект)
Декларацию списка типов возвращаемого значения можно записывать каждый с новой строки
// Возвращаемое значение:
// - Структура
// - ТаблицаЗначений
Функция ОбработкаОбъекта(Объект)
Бесполезная ссылка на функцию-конструктор в описании к параметру
// Параметры:
// Объект - ТаблицаЗначений - См. ОбщегоНазначения.НовыйОбъектДанных
Процедура ОбработкаОбъекта(Объект)
Ссылка на тип не комбинируется с описанием для текущего элемента, должны быть записаны вместо типа
// Параметры:
// Объект - См. ОбщегоНазначения.НовыйОбъектДанных
Процедура ОбработкаОбъекта(Объект)
В возвращаемом значении функции можно указывать ссылки на тип
// В возвращаемом значении функции можно указывать
//
// Возвращаемое значение:
// См. Справочник.Товары.ЕдиницыИзмерения
Функция ОбработкаОбъекта(Объект)
В возвращаемом значении функции можно указывать ссылки на локальные не экспортные функции конструкторы объектов данных, если функция должна возвращать заполненный объект, но модуль не должен позволять через API создавать новый пустой объект данных
// Экспорт из модуля типа объекта в функции, создающем объект и заполняющем значения,
// функция-конструктор остается не доступной для потребителей
//
// Возвращаемое значение:
// См. НовыйОбъектДанных
Функция ОбработкаОбъекта(Объект) Экспорт
Система типизации 1C:EDT поддерживает ссылки на типы вместо их прямого указания. Использовать ссылки на типы удобно для сокращения объема текста в документирующих комментариях. Так же, это повышает точность описания типов при изменении сложных объектов данных и не требует модификаций при рефакторинге.
Множество различных объектов метаданных производят коллекции типов. Документирующий комментарий позволяет ссылаться на этот тип.
Рассмотрим различные примеры ссылок на такие типы.
ПРАВИЛЬНО:
// Параметры:
// Объект - См. Справочник.Товары.ЕдиницыИзмерения
Процедура ОбработкаОбъекта(Объект)
Такая ссылка еще не поддерживается в 1C:EDT!
ПРАВИЛЬНО:
// Параметры:
// Объект - СтрокаТабличнойЧасти: См. Справочник.Товары.ЕдиницыИзмерения
Процедура ОбработкаОбъекта(Объект)
ПРАВИЛЬНО:
// Параметры:
// Реквизит1 - См. Справочник.Товары.Артикул
Процедура ОбработкаОбъекта(Реквизит1)
ПРАВИЛЬНО:
// Параметры:
// РеквизитТЧ - См. Справочник.Товары.ЕдиницыИзмерения.Единица
Процедура ОбработкаОбъекта(РеквизитТЧ)
// Parameters:
// Объект - См. XDTOПакет.КонтактнаяИнформация.Адрес
Процедура ОбработкаОбъекта(Объект)
Явное использование типов объектов XDTO в коде при указании пространства имен и имени типа в строковом литерале:
ТипАдрес = ФабрикаXDTO.Тип("http://www.sample-package.org", "Адрес");
Адрес = ФабрикаXDTO.Создать(ТипАдрес);
Адрес.Улица = "...";
Иногда необходимо добавить сложную логику при создании объетов на основе фабрики:
// Зарашиваем имя пакета в зависимости от версии
ПространсвтоИмен = ПлучитьПространствоИмен(ВерсияПакета);
// В этом месте реальный тип не вычисляется, т.к. точное имя пакета XDTO не известно
ТипАдрес = ФабрикаXDTO.Тип(ПространсвтоИмен, "Адрес");
// Указываем тип переменной со ссылкой на тип из конкретного пакета
Адрес = ФабрикаXDTO.Создать(ТипАдрес); // См. XDTOПакет.КонтактнаяИнформация.Адрес
Адрес.Улица = "...";
Ссылка на форму указывается по полному имени формы
ПРАВИЛЬНО:
// Параметры:
// Форма - См. Справочник.Товары.Форма.ФормаЭлемента
Процедура ОбработкаОбъекта(Форма)
Ссылка тип реквизита формы
ПРАВИЛЬНО:
// Параметры:
// Объект - См. Справочник.Товары.Форма.ФормаЭлемента.Объект
Процедура ОбработкаОбъекта(Объект)
Ссылка тип элемента формы
ПРАВИЛЬНО:
// Параметры:
// Список - См. Справочник.Товары.Форма.ФормаСписка.Элементы.Список
Процедура ОбработкаОбъекта(Список)
Использование ссылки на тип текущих данных динамического списка на форме не поддерживается в документирующих комментариях. Вместо этого следует передавать сам элемент формы и далее обрабатывать ТекущиеДанные
ПРАВИЛЬНО:
// Параметры:
// Список - См. Справочник.Товары.Форма.ФормаСписка.Элементы.Список
Процедура ОбработкаОбъекта(Список)
ЗначениеАртикула = Список.ТекущиеДанные.Артикул;
...
Такая ссылка еще не поддерживается в 1C:EDT!
ПРАВИЛЬНО:
// Параметры:
// СтрокаТЗ - ДанныеФормыЭлементКоллекции: См. Справочник.Товары.Форма.ФормаСписка.Элементы.ТЗ
Процедура ОбработкаОбъекта(СтрокаТЗ)
В ссылка типизирующих комментариев можно переиспользовать описанные типы из возвращаемого значения функций или входящих параметров метода.
Ссылка на тип параметра экспортного метода из модуля менеджера
ПРАВИЛЬНО:
// Параметры:
// Список - См. Справочники.Товары.МетодМодуляМенеджера.Параметр1
Процедура ОбработкаОбъекта(Список)
Ссылка на тип параметра экспортного метода из модуля объекта
ПРАВИЛЬНО:
// Параметры:
// Список - См. СправочникОбъект.Товары.МетодМодуляОбъекта.Параметр2
Процедура ОбработкаОбъекта(Список)
При размещении процедур в общих модулях (обычно "Переопределяемый") из общих процедуры могут быть вызваны наследники какого-либо механизма библиотеки.
ПРАВИЛЬНО:
// Параметры:
// Список - См. СправочникОбъект.Товары.МетодМодуляОбъекта.Параметр2
// Реквизит - См. Справочник.Товары.ЕдиницыИзмерения.Единица
// Объект - СправочникОбъект.Товары
Процедура ОбработкаОбъекта(Список, Реквизит, Объект) Экспорт
Документы.РеализацияТоваров.ОбработкаОбъекта(Список, Реквизит, Объект);
Документы.ПоступлениеТоваров.ОбработкаОбъекта(Список, Реквизит, Объект);
...
В модуле менеджера соответствующих объектов можно сослаться на сигнатуру параметров метода, чтобы не описывать полностью все типы. Необходимо указать только ссылку на метод, других комментариев или элементов документирующих комментариев быть не должно.
ПРАВИЛЬНО:
// См. ОбщийМодульПодсистема1Переопределяемый.ОбработкаОбъекта
Процедура ОбработкаОбъекта(Список, Реквизит, Объект)
В этом случае будет выполнено сопоставление имен параметров текущего метода с именами параметров метода "интерфейса".
Для локальных переменных возможно указание типов в строке инициализации.
Процедура ОбработкаФормы(Форма, ИмяРеквизита)
Данные = Форма[ИмяРеквизита]; // ПолеВвода - опциональное описание, почему переопределяем тип
Поддерживаются ссылки на типы:
Данные = ПолучитьИзВременногоХранилища(Адрес); // см. НовыйОбъектДанных
Внимание! В целом, такой подход следует считать исключеним и не практиковать в коде, если возможно спроектировать код более прозрачно для вычисления типов.
Здесь собраны примеры решения различных задач типизации. Если вы не нашли здесь какой-либо случай, но самостоятельно разобрались как правильно решать - просим вас добавить пример на эту страницу через контрибутинг в проект.
Перем
т.к. такая переменная инициализируется с типом Неопределенно
и дальнейшая смена типа значения может быть не видна для статического анализатораНЕПРАВИЛЬНО:
Процедура ОбработкаТекущейСтроки(ТЧ)
Перем ТекущаяСсылка;
Для каждого СтокаТЧ из ТЧ Цикл
ТекущаяСсылка = СтрокаТЧ.Ссылка;
...
КонецЦикла;
Объект = ТекущаяСсылка.ПолучитьОбъект();
...
ПРАВИЛЬНО:
Процедура ОбработкаТекущейСтроки(ТЧ)
ТекущаяСсылка = Справочники.Номенклатура.ПустаяСсылка();
Для каждого СтокаТЧ из ТЧ Цикл
ТекущаяСсылка = СтрокаТЧ.Ссылка;
...
КонецЦикла;
Объект = ТекущаяСсылка.ПолучитьОбъект();
...
НЕПРАВИЛЬНО:
...
Перем ИдентификаторСтрокиПравилаВыгрузки;
...
Если НЕ ТелоСообщения.Свойство("ИдентификаторСтрокиПравилаВыгрузки", ИдентификаторСтрокиПравилаВыгрузки) Тогда
ИдентификаторСтрокиПравилаВыгрузки = СловарьМС.ПустойИдентификатор();
КонецЕсли;
ПРАВИЛЬНО:
...
ИдентификаторСтрокиПравилаВыгрузки = СловарьМС.ПустойИдентификатор();
Если ТелоСообщения.Свойство("ИдентификаторСтрокиПравилаВыгрузки") Тогда
ИдентификаторСтрокиПравилаВыгрузки = ТелоСообщения.ИдентификаторСтрокиПравилаВыгрузки;
КонецЕсли;
НЕПРАВИЛЬНО:
// Создает новый объект Номенклатуры по переданному типу
МойОбъект = ОбщийМодуль.СоздатьНовыйОбъектПоТипу(ТипОбъекта);
ПРАВИЛЬНО:
МойОбъект = ОбщийМодуль.СоздатьНовыйОбъектПоТипу(ТипОбъекта); // СправочникОбъект.Номенклатура -
Текущей функциональностью 1C:EDT является запись типа в одну строку в комментарии - что исключает местное описание сложных объектов данных (ТЗ, Структура, массив из структур) - для них необходимо использовать ссылки на функции конструкторы этих объектов.
ПРАВИЛЬНО:
МойОбъект = Параметры.МойОбъект; // см. НовыйОбъектДанных
Допускается применение типизатора созданного через Новый ОписаниеТипов(...)
для формирования переменных с необходимым типом начального пустого значения.
ПРАВИЛЬНО:
Типизатор = Новый ОписаниеТипов("СправочникСсылка.Номенклатура,СправочникСсылка.НоменклатураПоставщика");
МояПеременная = Типизатор.ПривестиЗначение(Неопределено);
Переменные модуля объекта, формы, конфигурации, включая глобальные переменные (экспортные), следует объявлять со статическим указанием типа в комментарии. Также следует инициализировать переменную модуля начальным/пустым значением в коде модуля (после всех процедур и функций). Для модуля формы допускается инициализация начального/пустого значения в обработчиках событий ПриСозданииНаСервере
для серверных переменных и в обработчике ПриОткрытии
для клиентских переменных.
Исключением могут быть не экспортные переменные модуля, используемые только внутри общих механизмов и не имеющие обращений внутри текущего модуля объекта или формы.
НЕПРАВИЛЬНО:
#Область ОписаниеПеременных
&НаКлиенте
Перем КэшированныеЗначения; //используется механизмом обработки изменения реквизитов ТЧ
&НаКлиенте
Перем ТекущиеДанныеИдентификатор; //используется для передачи текущей строки в обработчик ожидания
&НаКлиенте
Перем ПараметрыДляЗаписи Экспорт;
#КонецОбласти
ПРАВИЛЬНО:
#Область ОписаниеПеременных
//используется механизмом обработки изменения реквизитов ТЧ
&НаКлиенте
Перем КэшированныеЗначения; // см. ОбработкаТабличнойЧастиКлиентСервер.ПолучитьСтруктуруКэшируемыеЗначения
//используется для передачи текущей строки в обработчик ожидания
&НаКлиенте
Перем ТекущиеДанныеИдентификатор; // Число -
&НаКлиенте
Перем ПараметрыДляЗаписи Экспорт; // Структура -
#КонецОбласти
....
ТекущиеДанныеИдентификатор = -1;
ПараметрыДляЗаписи = Новый Структура;
НЕПРАВИЛЬНО:
Процедура Обработка()
СправочникОбъект = Справочники.Номенклатура.СоздатьЭлемент();
...
Параметры = Новый Структура("Ссылка");
Параметры.Ссылка = СправочникОбъект.Ссылка;
ПРАВИЛЬНО:
Процедура Обработка()
СправочникОбъект = Справочники.Номенклатура.СоздатьЭлемент();
...
Параметры = Новый Структура("Ссылка", Справочники.Номенклатура.ПустаяСсылка());
Параметры.Ссылка = СправочникОбъект.Ссылка;
ПРАВИЛЬНО:
Процедура Обработка()
СправочникОбъект = Справочники.Номенклатура.СоздатьЭлемент();
...
Параметры = Новый Структура;
Параметры.Вставить("Ссылка", СправочникОбъект.Ссылка);
НЕПРАВИЛЬНО:
Процедура Обработка()
Параметры = Новый Структура;
Если НеобходимоЗаполнить Тогда
ОбщийМодуль.ЗаполнитьПараметры(Параметры);
КонецЕсли;
...
Если Параметры.МоеСвойство = ...
...
ПРАВИЛЬНО:
Процедура Обработка()
Параметры = Новый Структура;
Параметры.Вставить("МоеСвойство", "Новое значение");
...
Если Параметры.МоеСвойство = ...
...
Процедура Обработка()
Если Структура.Свойство("МоеСвойство") И ЗначениеЗаполнено(Структура.МоеСвойство) Тогда
МоеСвойство = Структура.МоеСвойство; // СправочникСсылка.Номенклатура - явное указание типа для неизвестного поля структуры
...
Функциональность будет реализована в 1C:EDT будущих версий.
НЕПРАВИЛЬНО:
Процедура Обработка()
Перем МояПеременная;
Если Структура.Свойство("МоеСвойство", МояПеременная) И МояПеременная = "Полученное значение" Тогда
...
ПРАВИЛЬНО:
Процедура Обработка()
МояПеременная = "";
Если Структура.Свойство("МоеСвойство", МояПеременная) И МояПеременная = "Полученное значение" Тогда
...
Новый Массив;
без указания типа его значений, если далее в коде текущего модуля происходит обращение к элементам массива.НЕПРАВИЛЬНО:
СписокСсылок = Новый Массив;
СписокСсылок.Добавить(Ссылка);
...
Для каждого Ссылка из СписокСсылок Цикл
Объект = Ссылка.ПолучитьОбъект();
...
ПРАВИЛЬНО:
СписокСсылок = Новый Массив; // Массив из СправочникСсылка.Номенклатура -
СписокСсылок.Добавить(Ссылка);
...
Для каждого Ссылка из СписокСсылок Цикл
Объект = Ссылка.ПолучитьОбъект();
...
ПРАВИЛЬНО:
СписокСсылок = НовыйСписокНоменклатуры();
СписокСсылок.Добавить(Ссылка);
...
Для каждого Ссылка из СписокСсылок Цикл
Объект = Ссылка.ПолучитьОбъект();
...
// Возвращаемое значение:
// Массив из СправочникСсылка.Номенклатура
Функция НовыйСписокНоменклатуры()
Возврат Новый Массив;
КонецФункции
ТаблицаЗначений
, ДеревоЗначений
всегда описывать все колонки и их типы.ПРАВИЛЬНО:
// Возвращаемое значение:
// ТаблицаЗначений:
// * Номенклатура - СправочникСсылка.Номенклатура
// * Характеристика - СправочникСсылка.ХарактеристикиНоменклатуры
// * Склад - СправочникСсылка.Склады
// * Количество - Число
// ...
Функция ТоварыДляСписания()
....
Возврат Таблица;
КонецФункции
ТаблицаЗначений
в качестве входящего параметра экспортного метода, с описанием колонок. Правильно использовать ссылку на функцию-конструктор создающий эту таблицу.НЕПРАВИЛЬНО:
// Параметры:
// Таблица - ТаблицаЗначений
// * Номенклатура - СправочникСсылка.Номенклатура
Процедура ОбработкаТаблицы(Таблица) Экспорт
Для каждого СтрокаТаблицы из Таблица Цикл
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
....
ПРАВИЛЬНО:
// Параметры:
// Таблица - см. ТоварыДляСписания
Процедура ОбработкаТаблицы(Таблица)
Для каждого СтрокаТаблицы из Таблица Цикл
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
....
НЕПРАВИЛЬНО:
// Параметры:
// Таблица - ТаблицаЗначений
Процедура ОбработкаТаблицы(Таблица) Экспорт
Для каждого СтрокаТаблицы из Таблица Цикл
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
....
ПРАВИЛЬНО:
// Параметры:
// Таблица - ТаблицаЗначений - произвольная таблица с товаром:
// * Номенклатура - СправочникСсылка.Номенклатура
Процедура ОбработкаТаблицы(Таблица) Экспорт
Для каждого СтрокаТаблицы из Таблица Цикл
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
....
СтрокаТЗ.Номенклатура = ...
а использует для обращения список колонок, сформированный в рантайме СтрокаТЗ[ИмяКолонки] = ...
.Следует использовать один из двух вариантов:
НЕПРАВИЛЬНО:
// Параметры:
// СтрокаТаблицы - СтрокаТаблицыЗначений
Процедура ОбработкаТаблицы(СтрокаТаблицы)
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
....
ПРАВИЛЬНО:
// Параметры:
// СтрокаТаблицы - СтрокаТаблицыЗначений:
// * Номенклатура - СправочникСсылка.Номенклатура
Процедура ОбработкаТаблицы(СтрокаТаблицы)
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
....
ПРАВИЛЬНО:
// Параметры:
// СтрокаТаблицы - СтрокаТаблицыЗначений: См. НоваяТаблицаСНоменклатурой
Процедура ОбработкаТаблицы(СтрокаТаблицы)
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПустаяСсылка();
....
// Возвращаемое значение:
// ТаблицаЗначений - с колонками:
// * Номенклатура - СправочникСсылка.Номенклатура -
Функция НоваяТаблицаСНоменклатурой()
....
Произвольный
, и необходимо создавать функцию конструктор которая инициализирует соответствие и описывает типы ключа и значения.ПРАВИЛЬНО:
// Возвращаемое значение:
// Соответствие из КлючИЗначение:
// * Ключ - Строка
// * Значение - Массив из ДокументОбъект
Функция НовоеСоответствие()
...
Для сложных типов, создаваемых на основе абстрактных платформенных типов (Структура
, Соответствие
, ТаблицаЗначений
, ДеревоЗначений
и др.), следует использовать функцию-конструктор данных.
Наименование функции следует выбирать как Новый
/Новая
/Новое
(New
) и наименование объекта данных.
ПРАВИЛЬНО:
// Возвращаемое значение:
// ТаблицаЗначений:
// * Номенклатура - СправочникСсылка.Номенклатура
Функция НоваяТаблицаОтобраннойНоменклатуры()
....
КонецФункции
При описании параметра метода следует указывать ссылку на функцию-конструктор данных без указания исходного базового типа данных (структура, таблица значений и т.д.).
НЕПРАВИЛЬНО 1:
// Заполняет список команд печати.
//
// Параметры:
// КомандыПечати - ТаблицаЗначений - состав полей см. в функции УправлениеПечатью.СоздатьКоллекциюКомандПечати.
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
НЕПРАВИЛЬНО 2:
// Заполняет список команд печати.
//
// состав полей см. в функции УправлениеПечатью.СоздатьКоллекциюКомандПечати.
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
НЕПРАВИЛЬНО 3:
// см. УправлениеПечатью.СоздатьКоллекциюКомандПечати.
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
НЕПРАВИЛЬНО 4:
// Заполняет список команд печати.
//
// Параметры:
// КомандыПечати - см. УправлениеПечатью.СоздатьКоллекциюКомандПечати.
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
НЕПРАВИЛЬНО 5:
// Заполняет список команд печати.
//
// Параметры:
// КомандыПечати - см. УправлениеПечатью.СоздатьКоллекциюКомандПечати - команды для заполнения
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
ПРАВИЛЬНО:
// Заполняет список команд печати.
//
// Параметры:
// КомандыПечати - см. УправлениеПечатью.СоздатьКоллекциюКомандПечати
//
Процедура ДобавитьКомандыПечати(КомандыПечати) Экспорт
При обработке более общих типов объектов в общих модулях может потребоваться получить заранее известный комплексный тип (Структура
, ТаблицаЗначений
, ДеревоЗначений
), при этом, функции-конструктора таких данных может не существовать, например, когда данные создаются объектом метаданных, формой, СКД и так далее. Для таких случаев следует использовать функцию-получатель, описывающую тип возвращаемого значения со всеми необходимыми свойствами/полями объекта. Для клиентских процедур не рекомендуется использовать конструкторы из модулей с контекстом 'Сервер', но без контекста 'Вызов сервера'.
НЕПРАВИЛЬНО:
// Параметры:
// Форма - ФормаКлиентскогоПриложения - форма, для элементов которых производится заполнение
// Параметры - Структура - дополнительные параметры дерева.
//
Процедура ОбновитьДеревоНовыхЭлементов(Форма, Параметры) Экспорт
ИмяЭлементаДерева = Параметры.ИмяЭлементаДерева;
...
ДеревоЭлементов = Форма.РеквизитФормыВЗначение(ИмяЭлементаДерева);
ДеревоЭлементов.Строки.Очистить();
...
СтрокаЭлемент = ДеревоЭлементов.Строки.Добавить();
СтрокаЭлемент.Наименование = ...;
ПРАВИЛЬНО:
// Параметры:
// Форма - ФормаКлиентскогоПриложения - форма, для элементов которых производится заполнение
// Параметры - Структура - дополнительные параметры дерева.
//
Процедура ОбновитьДеревоНовыхЭлементов(Форма, Параметры) Экспорт
ИмяЭлементаДерева = Параметры.ИмяЭлементаДерева;
...
ДеревоЭлементов = ДеревоНовыхЭлементов(Форма, ИмяЭлементаДерева);
ДеревоЭлементов.Строки.Очистить();
...
СтрокаЭлемент = ДеревоЭлементов.Строки.Добавить();
СтрокаЭлемент.Наименование = ...;
КонецПроцедуры
// Параметры:
// ...
//
// Возвращаемое значение:
// ДеревоЗначений:
// * Наименование - Строка
// * ВидЭлемента - ...
// * ...
Функция ДеревоНовыхЭлементов(Форма, ИмяЭлементаДерева)
Возврат Форма.РеквизитФормыВЗначение(ИмяЭлементаДерева);
КонецФункции
Для параметров экспортных методов рекомендуется указывать ссылку на функцию-конструктор таких объектов.
Не рекомендуется указывать в качестве параметров не экспортных методов сложные типы на основе Массивов
, Таблиц Значений
, Структур
и т.д., если объект является цельным, созданным в текущем модуле и контекст передачи объекта ограничен текущим модулем. В этом случае 1C:EDT не выполняет динамическую типизацию таких параметров, а использует указанные статические типы в описании метода.
Допускается описание таких типов во входящих параметрах, если описывается часть объекта или программный интерфейс объекта, например несколько колонок ТЧ.Товары
для которых выполняется расчет, при этом не существует одной единой функции-конструктора на которую можно сослаться в описании.
Существует понятие "описания программного интерфейса объекта" и его реализация в прикладных объектах конфигурации. С применением библиотечного подхода к разработке конфигураций, библиотека может описывать некий программный интерфейс который должен быть реализован в прикладном объекте, для того чтобы библиотечный механизм имел доступ к объекту.
Например, механизм "Свойства" из библиотеки БСП описывает интерфейс объекта: Наличие табличной части ДополнительныеРеквизиты
, содержит колонки Свойство
, Значение
, ТекстоваяСтрока
с определенными типами. Далее общий механизм библиотеки может обращаться к объекту например, при записи УправлениеСвойствами.ПередЗаписьюНаСервере(ЭтотОбъект, ТекущийОбъект);
объекта из формы.
Следует описывать интерфейс входящего объекта для той части объекта, которая требуется для работы механизма. При этом, следует учитывать, что механизм расширений свойств в документирующих комментариях поддерживается для тех типов, у которых возможны пользовательские свойства. Например: элементы коллекции вместо самих коллекций - тип ТабличнаяЧасть
не имеет пользовательских свойств, а тип СтрокаТабличнойЧасти
может иметь; тип ДанныеФормыКоллекция
не имеет пользовательских свойств, а тип ДанныеФормыЭлементКоллекции
может иметь.
НЕПРАВИЛЬНО:
// Параметры:
// Форма - ФормаКлиентскогоПриложения - уже настроена в процедуре ПриСозданииНаСервере:
// * Элементы - ВсеЭлементыФормы:
// ** ДополнительныеРеквизиты - ГруппаФормы
// * Свойства_ИспользоватьСвойства - Булево
// * Свойства_ИспользоватьДопРеквизиты - Булево
// ....
//
// Объект - Неопределено - взять объект из реквизита формы "Объект".
// - СправочникОбъект, ДокументОбъект, ДанныеФормыСтруктура - (по типу объекта) где:
// * ДополнительныеРеквизиты - ТабличнаяЧасть, ДанныеФормыКоллекция:
// ** Свойство - ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения -
// ** Значение - Характеристика.ДополнительныеРеквизитыИСведения -
// ** ТекстоваяСтрока - Строка -
Процедура ПеренестиЗначенияИзРеквизитовФормыВОбъект(Форма, Объект = Неопределено, ПередЗаписью = Ложь) Экспорт
Если НЕ Форма.Свойства_ИспользоватьСвойства
ИЛИ НЕ Форма.Свойства_ИспользоватьДопРеквизиты Тогда
...
СтарыеЗначения = Объект.ДополнительныеРеквизиты.Выгрузить();
Объект.ДополнительныеРеквизиты.Очистить();
...
ПРАВИЛЬНО:
// Параметры:
// Форма - ФормаКлиентскогоПриложения - уже настроена в процедуре ПриСозданииНаСервере:
// * Элементы - ВсеЭлементыФормы:
// ** ДополнительныеРеквизиты - ГруппаФормы
// * Свойства_ИспользоватьСвойства - Булево
// * Свойства_ИспользоватьДопРеквизиты - Булево
// ....
//
// Объект - Неопределено - взять объект из реквизита формы "Объект".
// - СправочникОбъект, ДокументОбъект, ДанныеФормыСтруктура - (по типу объекта) где:
// * ДополнительныеРеквизиты - ТабличнаяЧасть Из СтрокаТабличнойЧасти:
// ** Свойство - ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения -
// ** Значение - Характеристика.ДополнительныеРеквизитыИСведения -
// ** ТекстоваяСтрока - Строка -
Процедура ПеренестиЗначенияИзРеквизитовФормыВОбъект(Форма, Объект = Неопределено, ПередЗаписью = Ложь) Экспорт
Если НЕ Форма.Свойства_ИспользоватьСвойства
ИЛИ НЕ Форма.Свойства_ИспользоватьДопРеквизиты Тогда
...
СтарыеЗначения = Объект.ДополнительныеРеквизиты.Выгрузить();
Объект.ДополнительныеРеквизиты.Очистить();
...
ПРАВИЛЬНО:
// Параметры:
// Форма - ФормаКлиентскогоПриложения:
// * Объект - ДанныеФормыСтруктура, СправочникОбъект, ДокументОбъект - основной реквизит формы
// * Элементы - ВсеЭлементыФормы:
// ** Товары - ТаблицаФормы - элемент таблицы товаров
Процедура ПриСозданииНаСервере(Форма)
Ссылка = Форма.Объект.Ссылка;
ТекущиеДанные = Форма.Элементы.Товары.ТекущиеДанные;
....
// Параметры:
// Форма - см. Справочник.Номенклатура.Форма.ФормаЭлемента
Процедура ПриСозданииНаСервере(Форма)
Ссылка = Форма.Объект.Ссылка;
Форма.Элементы.Артикул.Видимость = Истина;
....
ФормаКлиентскогоПриложения
следует использовать соответствующие типы расширений управляемой формы: РасширениеУправляемойФормыДляОбъектов
, РасширениеУправляемойФормыДляДокумента
, РасширениеУправляемойФормыДляДинамическогоСписка
и так далее.// Параметры:
// Форма - РасширениеУправляемойФормыДляОбъектов -
Процедура ОбработкаЗакрытия(Форма) Экспорт
....
Форма.Записать();
....
ПолучитьФорму()
и ОткрытьФорму()
с присвоением возвращаемого значения формы после открытия - следует указывать строковый литерал с полным именем формы первым параметром.ФормаКлиентскогоПриложения
а не конкретный тип формы справочника номенклатуры, и весь контекст формы не будет доступен. В 1C:EDT на текущий момент поддерживается полная типизация только для полных имен форм, ссылки на основные формы для объекта метаданного ФормаОбъекта
, ФормаСписка
и т.д. возвращают общий тип ФормаКлиентскогоПриложения
, полная типизация может быть поддержана в будущих версиях.НЕПРАВИЛЬНО:
ИмяФормы = "Справочник.Номенклатура.Форма.ФормаЭлемента";
Форма = ПолучитьФорму(ИмяФормы);
ПРАВИЛЬНО:
Форма = ПолучитьФорму("Справочник.Номенклатура.Форма.ФормаЭлемента");
// или
Форма = Справочники.Номенклатура.ПолучитьФорму("ФормаЭлемента");
Данные = ПолучитьИзВременногоХранилища(Адрес); // см. НовыйОбъектДанных
ДополнительныеПараметры
у объектов, или Параметры
формы, пользовательские параметры элементов СКД
, ДополнительныеПараметры
у обработчиков оповещения и так далее.Не следует обращаться к элементу именованной коллекции, например ВсеЭлементыФормы
и другие, через строковый индекс с именем элемента. Вместо этого следует обращаться напрямую к элементу так как в этом случае статический анализатор может контролировать наличие элемента, его тип.
НЕПРАВИЛЬНО:
Элементы["Наименование"].Видимость = Ложь;
ПРАВИЛЬНО:
Элементы.Наименование.Видимость = Ложь;
Исключением может быть:
НЕПРАВИЛЬНО:
Элементы["Наименование"].Видимость = Ложь;
Элементы["Наименование"].Доступность = Истина;
ПРАВИЛЬНО:
Элемент = Элементы["Наименование"]; // ПолеФормы -
Элемент.Видимость = Ложь;
Элемент.Доступность = Истина;
ПРАВИЛЬНО:
Элемент = Элементы.Найти("Наименование");
Если Элемент <> Неопределено Тогда
Элемент.Видимость = Ложь;
...
ПРАВИЛЬНО:
Если Параметры.Свойство("Ссылка") Тогда
Ссылка = Параметры["Ссылка"]; // СправочникСсылка -
...
Реквизит формы с типом Произвольный
в коде следует рассматривать как "черный ящик". Статический анализатор не отслеживает изменение типа реквизита формы, поэтому весь обслуживающий этот реквизит код должен использовать проверку типа значения.
В общем случае не следует использовать реквизит с типом Произвольный
на форме, т.к. при этом разработчик самостоятельно несет ответственность за инициализацию значения в этом реквизите, за то, что все типы данных хранимые в реквизите могут быть сериализованы/десериализованы при передаче с клиента на сервер и обратно. Так же значение реквизита будет передаваться между клиентом и сервером всегда т.к. Платформа не контролирует модификацию значений, например внутри структуры, помещенной в произвольный реквизит.
Реквизит с типом Произвольный
следует заменять на честные реквизиты формы с определенными типами. Исключением может быть хранимые данные общих механизмов библиотек, которые через программный интерфейс инициализируют и обрабатывают хранимое в этом реквизите значение.
Если заменить реквизит с типом Произвольный
нет возможности, следует использовать функцию-конструктор для инициализации значения и дальнейших ссылок на типы. При этом не следует напрямую обращаться к реквизиту - для получения значения следует использовать функцию-получатель.
ПРАВИЛЬНО:
// Возвращаемое значение:
// Структура:
// * Ссылка - СправочникСсылка.Номенклатура - ссылка на текущую номенклутру
// ...
Функция НовыйСложныйОбъектДанных()
Данные = Новый Структура;
Данные.Вставить("Ссылка", ...);
...
Возврат Данные;
КонецФункции
// Возвращаемое значение:
// см. НовыйСложныйОбъектДанных
Функция РеквизитПроизвольный()
Возврат РеквизитПроизвольный;
КонецФункции
...
// Инициализация реквизита через функцию-конструктор
РеквизитПроизвольный = НовыйСложныйОбъектДанных();
// Обращение к значению в реквизите с произвольным типом
Ссылка = РеквизитПроизвольный().Ссылка;
При типизации выборки/выгрузки из результата запроса следует использовать возможности:
НЕПРАВИЛЬНО:
Запрос = Новый Запрос;
Запрос.Текст =
ТексЗапросаОстатков()
+ ТекстЗапросаРезервов();
РезультаЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Ссылка = Выборка.Ссылка.ПолучитьОбъект();
...
ПРАВИЛЬНО:
// Возвращаемое значение:
// ВыборкаИзРезультатаЗапроса:
// * Номенклатура - СправочникСсылка.Номенклатура
Функция ОстаткиДляОбработки()
Запрос = Новый Запрос;
Запрос.Текст =
ТексЗапросаОстатков()
+ ТекстЗапросаРезервов();
РезультаЗапроса = Запрос.Выполнить();
Возврат РезультатЗапроса.Выбрать();
КонецФункции;
...
Выборка = ОстаткиДляОбработки();
Пока Выборка.Следующий() Цикл
Ссылка = Выборка.Номенклатура.ПолучитьОбъект();
...
ПРАВИЛЬНО:
Запрос = Новый Запрос;
Запрос.Текст = "
| ВЫБРАТЬ
| Номенклатура
|ИЗ
| РегистраНакопления.Остатки.Остатки
|
| ОБЪДИНИТЬ ВСЕ
|
|ВЫБРАТЬ
| Номенклатура
|ИЗ
| РегистрНакопления.Резервы.Остатки
|";
РезультаЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Ссылка = Выборка.Номенклатура.ПолучитьОбъект();
...
Объекты данных созданные пользовательским кодом и использованные вне текущего модуля - должны быть описаны функцией возвращающей значение.
Использование типа созданного в текущем модуле, но не предназначенного для создания в другом модуле - следует использовать не экспортную функцию-конструктор, при этом существует 2 варианта: 1. Экспортная функция, которая возвращает это значение вместе с данными (функция-получатель) - в ней нужно в возвращаемом значении указать функцию-конструктор 2. Реализация какого-либо интерфейса из переопределяемого модуля - в этом случае, можно использовать ссылку на параметр
Макет = УправлениеПечатью.МакетПечатнойФормы("Документ.РеализацияТоваровУслуг.ПечатнаяФорма"); //см. Документ.РеализацияТоваровУслуг.Макет.ПечатнаяФорма
Структура + СправочникОбъект.Номенклатура
чтобы не описывать весь тип. При этом можно добавить в описание дополнительные колонки, которые вводятся для технических целей (помощь при копировании, передача дополнительной информации с объектом).