简体   繁体   English

关闭表单时C#ArgumentOutOfRangeException

[英]C# ArgumentOutOfRangeException when closing forms

I am writing a WinForms C# Program. 我正在编写WinForms C#程序。

I am trying to close all forms except my main form, FrmMain . 我正在尝试关闭除主窗体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. 一种是我的主窗体,另一种是用ShowDialog()方法显示的窗体。

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 . 出于某种原因,当我不设置断点并运行此特定代码段时,会收到ArgumentOutOfRangeException因为变量i达到了-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. for循环一直持续到i达到-1是没有意义的,因为我有i >= 0条件。

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? 有人可以向我解释为什么当我不使用断点时i的索引变为-1 ,而当我使用断点并逐个遍历循环的每一行时为什么索引变为0

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. 我阻止获取ArgumentOutOfRangeException的方法是在for循环内添加另一个变量。 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. 本质上, for循环仅在条件为false时终止,这意味着i必须先达到-1才能停止。 See When does iteration variable in for loop increment should provides a good explanation. 请参阅何时for循环增量中的迭代变量应提供良好的解释。

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. 结合您使用BeginInvoke的事实,它实际上将执行移动到单独的线程(这意味着执行可能会延迟),并且i是一个捕获变量,当调用Dispose()时, i完全有可能为-1

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? 您可以在此处找到有关捕获的变量的信息: .NET中的“闭包”是什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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