Как исправить ошибку «Значение индекса выходит за границы диапазона» при обработке данных в 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

Исключительная ситуация с текстом «Значение индекса выходит за границы диапазона» возникает в платформе 1С:Предприятие при попытке программного обращения к несуществующему элементу коллекции. Чаще всего разработчики сталкиваются с этим при получении элементов из таких объектов, как СписокЗначений, Массив или ТаблицаЗначений через метод Получить(Индекс) или оператор квадратных скобок [Индекс].

Разберем типичный сценарий возникновения этой ошибки, выясним ее истинные причины и рассмотрим по шагам, как локализовать сбой и правильно переписать код.

Анализ проблемного кода и механизма возникновения ошибки

Рассмотрим распространенную ситуацию: разработчик получает данные из реквизита формы и пытается извлечь первый элемент списка для последующей передачи в функцию формирования XML или печатной формы:


&НаКлиенте
Процедура ВыгрузитьДанные()
    СписокРеализаций = ЭтаФорма.Объект.Ссылки;
    ЗаписьXML.ЗаписатьНачалоЭлемента("DocumentNumber");
    
    // Ошибка: Значение индекса выходит за границы диапазона
    НомерФайла = НомерТТН(СписокРеализаций.Получить(0).Значение);
    ЗаписьXML.ЗаписатьТекст(Прав(НомерФайла.Номер, 6));
КонецПроцедуры

При выполнении строки с методом Получить(0) платформа генерирует исключение. Причина заключается в том, что коллекция СписокРеализаций в момент вызова пуста. Нумерация индексов в 1С начинается с 0, но если в коллекции содержится 0 элементов, обращение к индексу 0 является недопустимым.

Выясним, почему список оказывается пустым, проанализировав серверную процедуру его заполнения:


&НаСервере
Процедура ЗапросНомеровРеализаций()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   РеализацияТоваровУслуг.Ссылка
        |ИЗ
        |   Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
        |ГДЕ
        |   РеализацияТоваровУслуг.Ссылка = &Ссылка";
    
    Запрос.УстановитьПараметр("Ссылка", ЭтаФорма.Объект.Рейс);
    РезультатЗапроса = Запрос.Выполнить();
    ВыборкаРеализаций = РезультатЗапроса.Выбрать();
    
    Пока ВыборкаРеализаций.Следующий() Цикл
        ЭтаФорма.Объект.Ссылки.Добавить(ВыборкаРеализаций.Ссылка);
    КонецЦикла;
КонецПроцедуры

Проанализируем ошибки, допущенные в этом алгоритме:

  1. Несоответствие типов и полей в секции ГДЕ: В условии запроса проверяется равенство РеализацияТоваровУслуг.Ссылка = &Ссылка, но в качестве параметра передается реквизит Рейс (имеющий тип ссылки на другой справочник или документ). В результате условие никогда не выполняется, и выборка всегда пуста.
  2. Неверная таблица метаданных: Данные могут храниться в другом типе документа (например, Документ.ПеремещениеТоваров вместо Документ.РеализацияТоваровУслуг).
  3. Отсутствие проверки количества элементов: Обращение по индексу Получить(0) выполняется напрямую без предварительной проверки заполненности коллекции.

Шаг 1. Исправление текста запроса и фильтрации данных

Для того чтобы запрос возвращал нужные документы, скорректируем поле фильтрации в секции ГДЕ. Сравнивать необходимо реквизит документа Рейс с переданным параметром рейса, а также обращаться к правильной таблице конфигурации:


&НаСервере
Процедура ЗаполнитьСписокДокументов()
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ДокументТаблица.Ссылка КАК Ссылка
        |ИЗ
        |   Документ.ПеремещениеТоваров КАК ДокументТаблица
        |ГДЕ
        |   ДокументТаблица.Рейс = &Рейс
        |   И НЕ ДокументТаблица.ПометкаУдаления";
    
    Запрос.УстановитьПараметр("Рейс", Объект.Рейс);
    РезультатЗапроса = Запрос.Выполнить();
    
    Если РезультатЗапроса.Пустой() Тогда
        ВызватьИсключение "Документов по выбранному рейсу не найдено.";
    КонецЕсли;
    
    Выборка = РезультатЗапроса.Выбрать();
    Объект.Ссылки.Очистить();
    
    Пока Выборка.Следующий() Цикл
        Объект.Ссылки.Добавить(Выборка.Ссылка);
    КонецЦикла;
КонецПроцедуры

Шаг 2. Безопасное обращение к элементам коллекций

Для предотвращения аварийного завершения работы всегда реализуем проверку наличия элементов перед обращением по индексу. Разберем два безопасных способа работы с коллекциями.

Способ 1. Проверка через метод Количество()


Если СписокРеализаций.Количество() > 0 Тогда
    ЭлементСписка = СписокРеализаций.Получить(0);
    СсылкаДляЗапроса = ЭлементСписка.Значение;
    НомерФайла = НомерТТН(СсылкаДляЗапроса);
Иначе
    // Обработка ситуации отсутствия данных
    Сообщить("Список документов пуст. Формирование XML прервано.");
    Возврат;
КонецЕсли;

Способ 2. Использование цикла «Для Каждого»

Если требуется обработать все элементы списка, наиболее надежным решением является цикл Для Каждого. Если коллекция пуста, тело цикла не выполнится ни разу, и ошибка выхода за границы диапазона гарантированно не возникнет:


Для Каждого Элемент Из СписокРеализаций Цикл
    СсылкаНаДокумент = Элемент.Значение;
    ДанныеДокумента = ПолучитьДанныеДокумента(СсылкаНаДокумент);
    
    ЗаписьXML.ЗаписатьНачалоЭлемента("DocumentNumber");
    ЗаписьXML.ЗаписатьТекст(Прав(ДанныеДокумента.Номер, 6));
    ЗаписьXML.ЗаписатьКонецЭлемента();
КонецЦикла;

Шаг 3. Оптимизация клиент-серверной архитектуры

Схема, при которой клиент поочередно вызывает сервер для получения реквизитов каждого отдельного документа, создает повышенную нагрузку на сеть и снижает производительность. Оптимальный подход — перенести всю выборку и формирование структуры файла на сторону сервера в единый контекст выполнения:


&НаСервереБезКонтекста
Функция СформироватьДанныеВыгрузки(Знач СсылкаНаРейс)
    СтруктураРезультата = Новый Массив;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ДокументТаблица.Номер КАК Номер,
        |   ДокументТаблица.Валюта КАК Валюта,
        |   ДокументТаблица.СуммаДокумента КАК СуммаДокумента,
        |   ДокументТаблица.Менеджер КАК Менеджер
        |ИЗ
        |   Документ.ПеремещениеТоваров КАК ДокументТаблица
        |ГДЕ
        |   ДокументТаблица.Рейс = &Рейс
        |   И НЕ ДокументТаблица.ПометкаУдаления";
    
    Запрос.УстановитьПараметр("Рейс", СсылкаНаРейс);
    РезультатЗапроса = Запрос.Выполнить();
    
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        Сведения = Новый Структура;
        Сведения.Вставить("Номер", Выборка.Номер);
        Сведения.Вставить("Валюта", Выборка.Валюта);
        Сведения.Вставить("СуммаДокумента", Выборка.СуммаДокумента);
        Сведения.Вставить("Менеджер", Выборка.Менеджер);
        
        СтруктураРезультата.Добавить(Сведения);
    КонецЦикла;
    
    Возврат СтруктураРезультата;
КонецФункции

Такой подход исключает создание промежуточных списков на форме, гарантирует корректность передаваемых параметров и полностью устраняет риск возникновения ошибок позиционирования по индексам.

← На главную