为什么ControlCollection不抛出InvalidOperationException? [英] Why does ControlCollection NOT throw InvalidOperationException?

查看:98
本文介绍了为什么ControlCollection不抛出InvalidOperationException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

遵循此问题用于处理跳过跳过迭代的控件的Foreach循环让我感到困惑的是,允许对变化的集合进行迭代:

Following this question Foreach loop for disposing controls skipping iterations it bugged me that iteration was allowed over a changing collection:

例如,以下内容:

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

投掷

InvalidOperationException:集合已修改;枚举操作可能无法执行.

InvalidOperationException: Collection was modified; enumeration operation may not execute.

但是,您可以在.Net表单中执行以下操作:

However in a .Net Form you can do:

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

跳过元素,因为迭代器运行在变化的集合上,没有引发异常

which skips elements because the the iterator runs over a changing collection, without throwing an exception

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

bug? aren't iterators required to throw InvalidOperationException if the underlaying collection changes?

所以我的问题是为什么在变化的ControlCollection上进行迭代时不会抛出InvalidOperationException?

So my question is Why does iteration over a changing ControlCollection NOT throw InvalidOperationException?

附录:

IEnumerator文档说:

The documentation for IEnumerator says:

枚举器没有对该集合的独占访问权;因此,通过集合进行枚举本质上不是线程安全的过程.即使同步了集合,其他线程仍然可以修改该集合,这会导致枚举器抛出异常.

推荐答案

对此的答案可以在

The answer to this can be found in 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()中明确解决此问题的注释.

Pay particular attention to the comments in MoveNext() which explicitly address this.

IMO这是一个误导的修复程序",因为它通过引入细微的错误掩盖了一个明显的错误(如OP所述,元素被悄悄地跳过了.)

IMO this is a misguided "fix" because it masks an obvious error by introducing a subtle one (elements are silently skipped, as noted by the OP).

这篇关于为什么ControlCollection不抛出InvalidOperationException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆