Как же тогда в таких случаях происходит обращение к атрибутам и методам? Дело в том, что значение агрегатного типа, у которого нет ссылки на объект доступа может существовать только для конкретных типов системы 1С:Предприятие - элементов справочников, документов, счетов бухгалтерского учета и т. п.. И здесь выручает внутренний идентификатор объекта, который всегда содержится в значении агрегатного типа и для указанных типов может предоставить исчерпывающую информацию, необходимую для создания объекта. А само создание объекта доступа производится при первом обращении его методу или атрибуту. Поясним вышесказанное на примере:
Тов = Док.Товар; // Объект доступа еще не создан, при условии, что ранее не было обращений к атрибутам и методам;
Тов2 = Док.Товар; // Аналогично
Цена = Тов.Цена; // Для переменной Тов создается объект доступа
Цена2 = Тов2.Цена; // Для переменной Тов2 создается объект доступа. Тов и Тов2 ссылаются на разные объекты доступа
Тов3 = Тов; // Тов и Тов3 ссылаются на один объект доступа
При создании объекта доступа происходит считывание данных объекта информационной базы. В дальнейшем значения прочитанных реквизитов остаются неизменными, вне зависимости от изменений, производимых в информационной базе. Поэтому не следует, сохранять в переменных на продолжительный период значения, соответствующие элементам справочников, документам и т. п., в надежде, что в их реквизитах будут отображаться актуальные на текущий момент значения.
Надо отметить, что объекты доступа продолжают существовать до тех пор, пока на них есть ссылки. Для приведенного выше примера уничтожение объектов, созданных для доступа к реквизитам элемента справочника может быть вызвано выполнением последовательности операторов:
Тов = 0; // Удалена ссылка на объект доступа
Тов2 = 0; // Уничтожен первый объект доступа
Тов3 = 0; // Уничтожен второй объект доступа
В результате выполнения этих операторов ссылки на объекты доступа удаляются путем присваивания переменным других значений. Ссылки на объекты доступа были бы также уничтожены при выходе из процедуры или функции, для которой переменные Тов, Тов2 и Тов3 были локальными. Если же переменная, содержащая ссылку на объект доступа, является глобальной переменной глобального модуля, то единственный способ уничтожить ссылку на объект доступа - это присвоить переменной другое значение.
Теперь рассмотрим случай, когда обращение к реквизиту происходит не через одну, как в рассмотренных выше примерах, а через две и более точек? Например, в случае выполнения оператора:
Цена = Док.Товар.Цена;
В этом случае, исполняющая система встроенного языка получает значение реквизита Товар документа, представленного значением переменной Док. При этом полученное значение не будет содержать ссылки на объект доступа. Затем, исполняющая система создает объект доступа, соответствующий реквизиту Товар, и, затем, с помощью созданного объекта, получает значение реквизита Цена. Затем объект доступа удаляется, так как ни одна из переменных после выполнения указанного оператора на объект не ссылается. Таким образом, при выполнении последовательности операторов
Наимен = Док.Товар.Наименование;
Цена = Док.Товар.Цена;
объект доступа, соответствующий Док.Товар будет дважды создан и дважды уничтожен. С точки зрения производительности для достижения той же цели было бы эффективнее воспользоваться последовательностью операторов:
Тов = Док.Товар; // Присваивается реквизит документа. Объект доступа еще не создан
Наимен = Тов.Наименование; // Для переменной Тов создается объект доступа
Цена = Тов.Цена; // Используется созданный ранее объект доступа
При выполнении данной последовательности объект для доступа к элементу справочника создается однократно и, после выполнения указанных операторов, переменная Тов сохранит ссылку на объект доступа и он сможет быть использован в дальнейшем, до тех пор, пока переменной не будет присвоено другое значение или произойдет возврат из процедуры или функции, в которой переменная определена.
Значения типов, соответствующих объектам информационной базы во встроенном языке
Для таких объектов информационной базы системы 1С:Предприятие как справочники, документы и счета бухгалтерского учета значения, представляющие эти объекты во встроенном языке могут выступать в двух разных видах:
- значения, полученные путем вызова системной функции СоздатьОбъект
- значения полученные из реквизитов форм и атрибутов объектов информационной базы
Значения, полученные при помощи вызова СоздатьОбъект() не представляют какой-то конкретный объект (элемент справочника, документ, счет бухгалтерского учета), а предназначены главным образом для обработки групп объектов. С помощью таких значений можно получать выборки множества объектов, последовательно обходить объекты, попавшие в выборку, производить их обновление, создавать новые и удалять существующие объекты и т. п.. Такие значения могут использоваться "многократно", то есть с помощью одного значения можно получить доступ сначала к одной выборке, потом к другой и так много раз.
Значения, содержащихся в реквизитах форм и атрибутах объектов информационной базы, являются точными значениями и представляют ровно один конкретный объект информационной базы (элемент справочника, документ, счет бухгалтерского учета). Такие значения также могут быть пустыми – не представляющими никакого объекта. С помощью таких значений можно получать доступ к атрибутам соответствующего объекта, но нельзя производить действий по созданию, удалению и изменению объекта.
Но несмотря на такие существенные различия оба описанных варианта значений одинаковы во многих проявлениях. Рассмотрим пример:
Спр1 = СоздатьОбъект("Справочник.Товары");
Спр2 = Док.Товар;
Переменные Спр1 и Спр2 содержат значения двух описанных выше видов. Для этих переменных способ доступа к атрибутам справочника производится одним и тем же способом. Многие методы объекта типа Справочник могут применяться как к Спр1, так и Спр2. Функции ТипЗначения() и ТипЗначенияСтр(), будучи примененными к Спр1 и Спр2 дадут одинаковые результаты. Многие методы встроенного языка также не различают какого вида значение передано им в качестве параметра: точное значение объекта или спозиционированная выборка.
И такое положение дел приводит к тому, что иногда у специалистов по конфигурированию возникают трудности с пониманием различия между приведенными видами значений. В результате при написании конфигураций возникают ситуации, когда одной и той же процедуре в качестве параметра могут передаваться значения разных видов:
1.
Спр1 = СоздатьОбъект("Справочник.Товары");
Спр1.ВыбратьЭлементы();
Пока Спр1.ПолучитьЭлемент() = 1 Цикл
Обработать(Спр1);
КонецЦикла;
2.
Спр2 = Док.Товар;
Обработать(Спр2);
В первом случае в качестве параметра процедуре Обработать() передается выборка, спозиционированная на конкретный элемент справочника, а во втором - точное значение элемента справочника. И, если, например, в процедуре Обработать() производится только считывание реквизитов справочника, то результаты, полученные в обоих случаях будут неразличимы. Но если в процедуре Обработать() производится присвоение переданного в качестве параметра значения реквизиту формы или атрибуту объекта (например, документа), то первый вариант просто не будет работать, так как вместо точного значения элемента справочника процедура получит выборку. Для того, чтобы все работало нормально первый вариант должен выглядеть так:
Спр1 = СоздатьОбъект("Справочник.Товары");
Спр1.ВыбратьЭлементы();
Пока Спр1.ПолучитьЭлемент() = 1 Цикл
Обработать(Спр1.ТекущийЭлемент());
КонецЦикла;
Функция ТекущийЭлемент() в качестве значения возвращает точное значение элемента справочника, на который спозиционирована выборка. А если функция ТекущийЭлемент() применяется к переменной, значением которой является уже точное значение элемента справочника, эта функция вернет само это значение. Так что равноценным вариантом решения показанной в примере проблемы было бы, если для выполнения действий процедура Обработать() использовала бы не сам переданный параметр, а значение некоторой переменной (например, Спр), значение которое получила бы из переданного параметра (Парам) следующим способом:
Спр = Парам.ТекущийЭлемент();
Однако следует иметь в виду, что при вызове метода ТекущийЭлемент() у переменной, значение которой получено из реквизитов форм и атрибутов объектов информационной базы, а не путем вызова функции СоздатьОбъект() будет выполняться поиск элемента справочника в информационной базе, что повлечет к дополнительным затратам времени. Соответственно, если полученное конкретное значение предполагается просто присвоить (например, измерению регистра), а не обращаться к его атрибутам и методам, и известно, что это именно конкретное значение, а не выборка, использовать метод ТекущийЭлемент() не следует. Поэтому можно рекомендовать создавать процедуры ориентированные на получение в качестве параметра только конкретного значения, а при вызове процедуры с передачей в качестве фактического параметра выборки вызывать метод ТекущийЭлемент().
Обработать(Спр1.ТекущийЭлемент());
Аналогичные соображения справедливы для объектов типа документ и счет бухгалтерского учета. Для документов аналогом функции ТекущийЭлемент() является функция ТекущийДокумент(), а для счетов бухгалтерского учета - ТекущийСчет().