简体   繁体   中英

C# ArgumentOutOfRangeException when closing forms

I am writing a WinForms C# Program.

I am trying to close all forms except my main form, FrmMain .

I must hide my main form.

I produced this by having two forms open. One with my main form, and one with another form shown with the ShowDialog() method.

When this code is executed on my machine, it appears that it should close all of the forms properly. For some reason, when I am not setting breakpoints and running this particular piece of code, I get an ArgumentOutOfRangeException because the variable i gets to the point where it is -1 . When I do set breakpoints, and slowly step through each piece of code it works fine.

It doesn't make sense for the for loop to continue all the way for i to get to -1 because I have the i >= 0 condition.

Can someone explain to me why the index of i gets to -1 when I am not using breakpoints but gets to 0 when I am using breakpoints and stepping through each line of the loop individually?

What can be done to fix this?

Thanks in advance.

            for (int i = Application.OpenForms.Count - 1; i >= 0; i--)
            {
                if (Application.OpenForms[i] is FrmMain)
                {
                    Application.OpenForms[i]?.BeginInvoke((MethodInvoker)delegate
                    {
                        Application.OpenForms[i]?.Hide();
                    });
                }
                else
                {
                    Application.OpenForms[i]?.BeginInvoke((MethodInvoker)delegate
                    {
                        Application.OpenForms[i]?.Dispose();
                    });
                }
            }

EDIT:

The way I prevented getting the ArgumentOutOfRangeException is by adding another variable inside the for loop. This is the code that I changed.

            for (int i = Application.OpenForms.Count - 1; i >= 0; i--)
            {
                int i1 = i;
                if (Application.OpenForms[i] is FrmMain)
                {
                    Application.OpenForms[i]?.BeginInvoke((MethodInvoker)delegate
                    {
                        Application.OpenForms[i1]?.Hide();
                    });
                }
                else
                {
                    Application.OpenForms[i]?.BeginInvoke((MethodInvoker)delegate
                    {
                        Application.OpenForms[i1]?.Dispose();
                    });
                }
            }

Essentially, the for loop only terminates when the condition is false, meaning i has to get to -1 before it will stop. See When does iteration variable in for loop increment should provides a good explanation.

Combined with the facts that you're using BeginInvoke , which essentially moves the execution to a separate thread (meaning it's execution could be delayed), and i is a captured variable it's entirely possible for i to be -1 when Dispose() is called.

When you've got breakpoints in place, you're probably slowing down the main thread execution enough that all the separate threads run in the expected order, so you won't see the problem.

You can find out about captured variables here: What are 'closures' in .NET?

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