InvalidOperationException

InvalidOperationException

在这个问题Foreach loop for disposing controls skipping iterations之后,我感到很困惑,因为允许更改集合进行迭代:

例如,以下内容:

List<Control> items = new List<Control>
{
    new TextBox {Text = "A", Top = 10},
    new TextBox {Text = "B", Top = 20},
    new TextBox {Text = "C", Top = 30},
    new TextBox {Text = "D", Top = 40},
};

foreach (var item in items)
{
    items.Remove(item);
}

抛出



但是,在.Net表单中,您可以执行以下操作:
this.Controls.Add(new TextBox {Text = "A", Top = 10});
this.Controls.Add(new TextBox {Text = "B", Top = 30});
this.Controls.Add(new TextBox {Text = "C", Top = 50});
this.Controls.Add(new TextBox {Text = "D", Top = 70});

foreach (Control control in this.Controls)
{
    control.Dispose();
}

跳过元素是因为迭代器在不断变化的集合上运行,而不会引发异常

漏洞?如果底层集合发生变化,是否不需要迭代器抛出InvalidOperationException

所以我的问题是,为什么在不断变化的ControlCollection上进行迭代不会引发InvalidOperationException?

附录:

documentation for IEnumerator 说:

最佳答案

答案可以在the Reference Source for ControlCollectionEnumerator 中找到

private class ControlCollectionEnumerator : IEnumerator {
    private ControlCollection controls;
    private int current;
    private int originalCount;

    public ControlCollectionEnumerator(ControlCollection controls) {
        this.controls = controls;
        this.originalCount = controls.Count;
        current = -1;
    }

    public bool MoveNext() {
        // VSWhidbey 448276
        // We have to use Controls.Count here because someone could have deleted
        // an item from the array.
        //
        // this can happen if someone does:
        //     foreach (Control c in Controls) { c.Dispose(); }
        //
        // We also dont want to iterate past the original size of the collection
        //
        // this can happen if someone does
        //     foreach (Control c in Controls) { c.Controls.Add(new Label()); }

        if (current < controls.Count - 1 && current < originalCount - 1) {
            current++;
            return true;
        }
        else {
            return false;
        }
    }

    public void Reset() {
        current = -1;
    }

    public object Current {
        get {
            if (current == -1) {
                return null;
            }
            else {
                return controls[current];
            }
        }
    }
}

请特别注意MoveNext()中的注释,这些注释可明确解决此问题。

IMO这是一个错误的“修补程序”,因为它通过引入一个细微的错误(如OP所指出的那样,所有元素被静默跳过)掩盖了一个明显的错误。

关于c# - 为什么ControlCollection不抛出InvalidOperationException?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35084463/

10-11 04:37