简体   繁体   中英

'accessibilityobject' threw an exception of type 'system.invalidoperationexception'

There are a lot of questions on SO about 'system.invalidoperationexception ' but none of them have helped me figure this out.

I have a datatable ( tab2tableExtra ) that gets its values from another datatable ( tab2table ), which in turn gets is values from a database. tab2tableExtra only contains 4 rows and 8 columns and all its values (barring column [0]) are calculated from tab2table . Specifically two columns in tab2table are used to drive a for loop and those seem to be at the crux of the problem. These are MLevel and RLevel , which are shown in the code below.

Everything works perfectly when both the MLevel column and RLevel column have some non-null values. But if one of those columns is all nulls ( DBNull.Value -which can happen on occasion), then something seems to go wrong. Interestingly, it doesn't actually cause the code to break, but it seems to mess with the calculated values in tab2tableExtra , as the entire table is null (except for column [0], which is just 1, 2, 3, 4).

Upon debugging, when either MLevel or RLevel (but not both) contains all null I see a 'system.invalidoperationexception from this`, as shown in the figure below. What causes the code to do is break out of the for loop after one iteration, and then not perform any of the rest of calculations. 错误讯息

This message comes from the following code:

// 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;

For reference, when I debug with a tab2table that has at least one non-null value in both MLevel and RLevel , I see this: 没有错误

If anyone knows how to solve this, or even just why this happening, it would be very useful.

In these lines of code:

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();

You're using int.TryParse to read the value of x["MLevel"] .

If x["MLevel"].ToString() doesn't return a string that can be parsed as an int then int.TryParse will return false. That includes if x is DBNull.Value . That won't get parsed as an int .

Then, after the TryParse , you have this: ? d : (int?)null) ? d : (int?)null)

In other words, if TryParse returned true - it was able to parse, then you're selecting d - the parsed value.

But if it couldn't parse the value - TryParse returned false - then you're returning (int?)null - which is effectively null.

At the end you're filtering the results for values between 1 and 4, and then counting the number of those results:

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

Just as you described, if there were some non-null values then that Count will probably return one or more. But if there are all null values then .Count will equal 0, because no values were between 1 and 4.

In that case countnumM and/or countnumRW would equal 0.

Further down you're setting some additional values if countnumM > 0 and if countnumRW > 0 . But they're not greater than 0. They are 0. If they are 0, you're code will do what you expect:

           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;
            } 

To clarify around the other part - the InvalidOperationException :

When you're in the debugger and you inspect the properties of a variable, it's going to try to display the value of each property. That's what the list of properties is in your image - it's all the properties of this .

Some of them might be properties you don't use or care about, but when it tries to read the properties so it can show them to you, the property throws an exception. So now instead of a property value it shows you the exception it got when trying to read the property.

This is understandably confusing because you're debugging trying to figure out what's going on in your code, and then you see exceptions. You wonder if they might be related to the problem.

Generally they aren't because if your code throws an exception then it stops execution of your code. That's an exception you would need to figure out. But if it doesn't stop your code from running and it's a property on some framework class (like Form.AccessibilityObject ) that you aren't even using, then you can usually ignore it.

As Scott Hannen said, the problem here has nothing to do with the 'system.invalidoperationexception' exception. For anyone who comes across a similar problem, the actually issue was with the null .

It turns out, in C# datatables cannot handle null values. And instead of giving an error, it simply just stops filling the datatable once it encounters one. In order to fix this, one has to make sure to use DBNull.Value . So in the code in question, for example, changing all null to DBNull.Value will fix the issue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM