«accessibilityobject» выдал исключение типа «system.invalidoperationexception» - PullRequest
0 голосов
/ 30 апреля 2019

Есть много вопросов по SO относительно 'system.invalidoperationexception ', но ни один из них не помог мне разобраться в этом.

У меня есть datatable (tab2tableExtra), который получает свои значения от другогоdatatable (tab2table), который в свою очередь получает значения из базы данных.tab2tableExtra содержит только 4 строки и 8 столбцов, и все его значения (столбец запрета [0]) рассчитываются из tab2table.В частности, два столбца в tab2table используются для запуска цикла for, и они, похоже, лежат в основе проблемы.Это MLevel и RLevel, которые показаны в приведенном ниже коде.

Все отлично работает, когда столбец MLevel и столбец RLevel имеют некоторые ненулевые значения.Но если один из этих столбцов равен нулю (DBNull.Value - что может случиться при определенных обстоятельствах), то что-то идет не так.Интересно, что на самом деле это не приводит к сбою кода, но, похоже, он портится с вычисленными значениями в tab2tableExtra, так как вся таблица пуста (за исключением столбца [0], который равен 1, 2, 3,4).

После отладки, когда либо MLevel, либо RLevel (но не оба) содержат все значения null, я вижу 'system.invalidoperationexception from this`, как показано на рисунке ниже.То, что заставляет код делать, это прерывание цикла for после одной итерации, а затем не выполнение каких-либо других вычислений.Error messages

Это сообщение исходит из следующего кода:

// Add values to tab2tableExtra
                // Add Levels columns
                DataRow row = tab2tableExtra.NewRow();
                for (int i = 1; i < 5; i++)
                {
                    row = tab2tableExtra.NewRow();
                    row["Level"] = i;
                    tab2tableExtra.Rows.Add(row);
                }
                // Add participation rate column values
                DataRow dr = tab2tableExtra.Rows[0];
                int rowCount = tab2table.Rows.Count;

                /*int countnumM = tab2table.AsEnumerable().Where(x => int.Parse(x["MLevel"].ToString()) == 1 || 
                                int.Parse(x["MLevel"].ToString()) == 2 || int.Parse(x["MLevel"].ToString()) == 3 || 
                                int.Parse(x["MLevel"].ToString()) == 4).ToList().Count;*/
                int countnumM = tab2table.AsEnumerable().Select(x => int.TryParse(x["MLevel"].ToString(), out var d) ? d : (int?)null).Where(x => x >= 1 && x <= 4).Count();
                int countnumRW = tab2table.AsEnumerable().Select(x => int.TryParse(x["RLevel"].ToString(), out var d) ? d : (int?)null).Where(x => x >= 1 && x <= 4).Count();

                /*int countnumRW = tab2table.AsEnumerable().Where(x => int.Parse(x["RLevel"].ToString()) == 1 || int.Parse(x["RLevel"].ToString()) == 2 ||
                                                    int.Parse(x["RLevel"].ToString()) == 3 || int.Parse(x["RLevel"].ToString()) == 4).ToList().Count;*/

                for (int i = 1; i < 5; i++)
                {
                    if (countnumM > 0)
                    {
                        float levelPercM = Convert.ToInt32(tab2table.Compute("COUNT(MLevel)", "MLevel =" + i.ToString()));
                        tab2tableExtra.Rows[i - 1][1] = Math.Round(100 * levelPercM / countnumM, 2);
                    }
                    else
                        tab2tableExtra.Rows[i - 1][1] = null;
                    if (countnumRW > 0)
                    {
                        decimal levelPercRW = Convert.ToDecimal(tab2table.Compute("COUNT([RLevel])", "RLevel =" + i.ToString()));
                        tab2tableExtra.Rows[i - 1][2] = Math.Round(100 * levelPercRW / countnumRW, 2);
                    }
                    else
                        tab2tableExtra.Rows[i - 1][2] = null;
                }
                // Add the rest of the column values that only require a single number
                tab2tableExtra.Rows[0][3] = rowCount;
                if (countnumM > 0)
                    tab2tableExtra.Rows[0][4] = 100*countnumM/rowCount;
                else
                    tab2tableExtra.Rows[0][4] = null;
                if (countnumRW > 0)
                    tab2tableExtra.Rows[0][5] = 100*countnumRW/rowCount;
                else
                    tab2tableExtra.Rows[0][5] = null;
                decimal RWavg = Convert.ToDecimal(tab2table.Compute("AVG([ROverall])", ""));
                decimal Mavg = Convert.ToDecimal(tab2table.Compute("AVG([MOverall])", ""));

                tab2tableExtra.Rows[0][6] = RWavg;
                tab2tableExtra.Rows[0][7] = Mavg;

Для справки, когда я отлаживаю с tab2table, который имеет по крайней мере одиннулевое значение в MLevel и RLevel, я вижу это: No Errors

Если кто-нибудь знает, как решить эту проблему, или даже просто, почему это происходит, это было бы оченьполезно.

Ответы [ 2 ]

1 голос
/ 30 апреля 2019

В этих строках кода:

int countnumM = tab2table.AsEnumerable()
    .Select(x => int.TryParse(x["MLevel"].ToString(), out var d) ? d : (int?)null)
    .Where(x => x >= 1 && x <= 4).Count();
int countnumRW = tab2table.AsEnumerable()
    .Select(x => int.TryParse(x["RLevel"].ToString(), out var d) ? d : (int?)null)
    .Where(x => x >= 1 && x <= 4).Count();

Вы используете int.TryParse, чтобы прочитать значение x["MLevel"].

Если x["MLevel"].ToString() не возвращает string, который может быть проанализирован как int, тогда int.TryParse вернет false. Это включает, если x равно DBNull.Value. Это не будет проанализировано как int.

Затем, после TryParse, у вас есть это: ? d : (int?)null)

Другими словами, если TryParse вернул true - он был в состоянии проанализировать, то вы выбираете d - проанализированное значение.

Но если он не смог разобрать значение - TryParse вернул false - тогда вы вернете (int?)null - что фактически равно нулю.

В конце вы фильтруете результаты по значениям от 1 до 4, а затем подсчитываете количество этих результатов:

.Where(x => x >= 1 && x <= 4).Count();

Как вы и описали, если бы было несколько ненулевых значений, то Count, вероятно, вернет одно или несколько. Но если есть все нулевые значения, то .Count будет равно 0, потому что между 1 и 4 не было значений.

В этом случае countnumM и / или countnumRW будет равно 0.

Далее вы устанавливаете некоторые дополнительные значения if countnumM > 0 и if countnumRW > 0. Но они не больше 0. Они равны 0. Если они равны 0, ваш код будет делать то, что вы ожидаете:

           for (int i = 1; i < 5; i++)
            {
                if (countnumM > 0) // this is == 0
                {
                    float levelPercM = Convert.ToInt32(tab2table.Compute("COUNT(MLevel)", "MLevel =" + i.ToString()));
                    tab2tableExtra.Rows[i - 1][1] = Math.Round(100 * levelPercM / countnumM, 2);
                }
                else               // This is what's happening
                    tab2tableExtra.Rows[i - 1][1] = null;

                if (countnumRW > 0) // this is == 0
                {
                    decimal levelPercRW = Convert.ToDecimal(tab2table.Compute("COUNT([RLevel])", "RLevel =" + i.ToString()));
                    tab2tableExtra.Rows[i - 1][2] = Math.Round(100 * levelPercRW / countnumRW, 2);
                }
                else                // This is what's happening
                    tab2tableExtra.Rows[i - 1][2] = null;
            } 

Чтобы уточнить вокруг другой части - InvalidOperationException:

Когда вы находитесь в отладчике и проверяете свойства переменной, он попытается отобразить значение каждого свойства. Вот что список свойств в вашем изображении - это все свойства this.

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

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

Как правило, это не так, потому что если ваш код выдает исключение, то он останавливает выполнение вашего кода. Это исключение, которое вы должны выяснить. Но если это не мешает вашему коду работать и это свойство некоторого каркасного класса (например, Form.AccessibilityObject), которое вы даже не используете, то вы обычно можете его игнорировать.

0 голосов
/ 06 мая 2019

Как сказал Скотт Ханнен, проблема здесь не имеет ничего общего с исключением 'system.invalidoperationexception'. Для тех, кто сталкивался с подобной проблемой, на самом деле проблема была с null.

Оказывается, в C # таблицы данных не могут обрабатывать null значений. И вместо того, чтобы выдавать ошибку, он просто прекращает заполнять таблицу данных, когда встречается с ней. Чтобы это исправить, нужно использовать DBNull.Value. Так, например, в рассматриваемом коде изменение всех null на DBNull.Value решит проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...