Как мне обработать исключение index out of range, не обработанное пользовательским кодом?

#c# #sql

#c# #sql

Вопрос:

У меня возникли проблемы с моей программой для работы. Все построено успешно, но при отладке я получил исключение index out of range в TotalUnits = Convert.ToDouble(значения [1].toString());. Предполагается, что программа вычисляет формулу и возвращает значение в текстовое поле. Я так запутался. Кто-нибудь, пожалуйста, может мне помочь? Спасибо.

Джастин

Вот некоторые из моего кода для просмотра:

 private double GetRefurbRate()
    {
        string sql = "";

        double Refurb_Rate = 0;

        double totalRefurb = 0;

       double totalUnits = 0;

       string error_msg = "";


        //Getting the value for sql for totalRefurb
        sql = "SELECT COUNT(distinct rp.repair_ord) "  
           "FROM "   schema   ".repair_part rp "  
           "WHERE rp.repair_type = 'REFURB' and rp.created_date > '"   DateTime.Now.ToString("d-MMM-yyyy")   "' ";


        while (true)
        {
            if (!myDb.RunSql(sql, true))
            {
                error_msg = "DBError for getting Refurb Rate";
                break;
            }
            if (myDb.dbRdr.HasRows)
            {
                if (myDb.dbRdr.Read())
                {


                    object[] values = new object[myDb.dbRdr.FieldCount];
                    myDb.dbRdr.GetValues(values);
                    Console.WriteLine(values[0].ToString());
                    totalRefurb = Convert.ToDouble(values[0].ToString());



                    //Getting the value from sql for totalUnits
                    sql = "SELECT count(distinct rp.repair_ord) "  
                        "FROM "   schema   ".repair_part rp "  
                        "WHERE rp.repair_type = 'REFURB' and rp.ref_desig is null  and rp.created_date > '"   DateTime.Now.ToString("d-MMM-yyyy")   "' ";



                    while (true)
                    {
                        if (!myDb.RunSql(sql, true))
                        {
                            error_msg = "DBError for getting Refurb Rate";
                            break;
                        }
                        if (myDb.dbRdr.HasRows)
                        {
                            if (myDb.dbRdr.Read())
                            {


                                values = new object[myDb.dbRdr.FieldCount];
                                myDb.dbRdr.GetValues(values);
                                Console.WriteLine(values[1].ToString());
                                totalUnits = Convert.ToDouble(values[1].ToString());

                                try
                                {

                                    //Formula for Refurb Rate
                                    Refurb_Rate = totalRefurb / totalUnits * 100;
                                    break;

                                }
                                catch (Exception e)
                                {
                                    Console.WriteLine(e);
                                }

                                myDb.dbRdr.Close();

                                if (error_msg != String.Empty)
                                {
                                    MessageBox.Show(error_msg, "Get Refurb Rate",
                                                    MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                                }

                                break;
                            }
                        }
                    }
                } 
            }
        }
        return Refurb_Rate;

    }
  

Комментарии:

1. Не имеет отношения к вашему вопросу, но, пожалуйста, обратите внимание: построение SQL-запросов с помощью конкатенации строк действительно плохо . Это приводит к уязвимостям SQL-инъекций. Посмотрите на использование параметризованных запросов.

Ответ №1:

Вы должны убедиться, что оно values[1] существует и что его можно преобразовать в double.

Кроме того, если объект является double , вам не нужно его преобразовывать, просто используйте приведение ( (double)values[1] или values[1] as double ).

Я не знаю, должен ли я сообщать, но на всякий случай массивы основаны на нуле, что означает, что если вы хотите сослаться на первый элемент в массиве, вы должны вы values[0] вместо values[1] . извините, если в этом не было необходимости.

Вам также следует пересмотреть удаление while (true) , если есть более простой способ сделать это, если вы не ожидаете неожиданного подсчета.

В вашем вопросе оба запроса возвращают только одно поле данных, и, следовательно, вы должны использовать values[0] в обоих случаях.

Комментарии:

1. Я не настолько опытен в программировании, поэтому любая информация хороша

Ответ №2:

Сначала вы должны проверить длину значений, убедиться, что индекс (в данном случае 1) меньше длины значений.

В целом, ваш код должен быть более структурированным и подготовленным для обработки условий ошибки (таких как отсутствие данных)

использование структурированной обработки исключений тоже может помочь. Поместите весь этот блок кода в блок try … catch.

Ответ №3:

Проблема, скорее всего, связана с возвратом, которого вы не ожидаете от своей базы данных. Где количество полей равно 0, и там для нет значений [1], и вы получаете исключение index

Ответ №4:

На основе вашего запроса:

 //Getting the value from sql for totalUnits
sql = "SELECT count(distinct rp.repair_ord) "   "FROM "   schema   ".repair_part rp "  
      "WHERE rp.repair_type = 'REFURB' and rp.ref_desig is null  and rp.created_date > '"   DateTime.Now.ToString("d-MMM-yyyy")   "' ";
  

Вы должны использовать значения [0] вместо значений [1], поскольку этот запрос вернет только 1 столбец count(distinct rp.repair_ord) . Либо это, либо запрос неверен, и вы хотите вернуть другие столбцы.

Комментарии:

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

2. @Justin, оба запроса возвращают 1 столбец, поэтому во втором запросе вы просто заменяете values переменную новым массивом, который снова содержит только один элемент, и поэтому он снова values[0] .

3. @Justin Ты просто используешь одну и ту же values переменную и 2 отдельных массива. Обратите внимание, как values назначается values = new object[] .

Ответ №5:

Вы захотите убедиться, что в массиве так много элементов…

 if (values.Length >= 2) myvar = values[1];
  

это позволит вам увидеть, что массив содержит такое количество объектов, прежде чем использовать его.

и имейте в виду, что массивы начинают свой отсчет с объекта 0, поэтому к любому объекту, к которому вы хотите получить доступ, на единицу меньше длины. вам нужно.

 it might be values.count im working from memory. let me know and i will ammend my post