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