C# 销毁类的效果

Posted

技术标签:

【中文标题】C# 销毁类的效果【英文标题】:C# Destroying the effects of a class 【发布时间】:2017-03-27 03:30:02 【问题描述】:

我有一个公共类拼图,它创建一个按钮拼图(按钮的二维数组)并将它们放在我的 Windows 窗体应用程序的 Form1 中(它将 Form1 设置为它们的父级)。当我调用一个函数来删除除 reset_button 之外的所有这些按钮时,它只会删除其中的一半。我必须调用此方法 n 次才能删除所有这些按钮,其中 n x n = 我的拼图所具有的按钮数。

public void Remove(Form g)
        
            for (int i=0; i<n;i++)
            foreach (Button b in g.Controls)
            
                if (b.Name!="btn_reset") b.Dispose();
            
        

Form1 类中的拼图是 Puzzle 类的新实例,Remove 是 Puzzle 类中的公共方法

btn_reset.MouseClick += (ss, ee) =>
            
                puzzle.Remove(this);
                //puzzle=new Puzzle(n,this);
            ;

知道为什么会这样吗?

【问题讨论】:

为什么你的 Remove 函数中有一个双重嵌套的 for 循环? @Nzall 因为我需要调用 foreach 循环 n 次才能处理所有按钮。否则每次只会处理其中的一半 【参考方案1】:

问题与foreach 和枚举的工作方式有关。

当您开始迭代 ControlCollection 时,会创建一个迭代器对象。该对象跟踪集合中的当前索引。但是现在您处理第一个控件 - 会发生什么?集合中的第一个控件被删除。但是迭代器不知道——它只是增加当前索引,并在被删除的那个之后跳过控件。

解决方案是创建控件集合的副本(例如g.Controls.OfType&lt;Button&gt;().Where(x =&gt; x.Name != "btn_reset").ToList()),或者使用简单的循环:

for (var i = 0; i < g.Controls.Count; i++)

  if (g.Controls[i].Name == "btn_reset") continue;

  g.Controls[i].Dispose();
  i--;

只有在没有副作用的情况下,枚举才是安全的 - 并且修改被枚举的集合绝对是一种副作用。在最近的集合(如List&lt;&gt;)中,迭代正在修改的集合会引发异常 - ControlCollection 太旧了。

【讨论】:

【参考方案2】:

您实际上并没有删除按钮,只是处理它们。我会建议这个代码:

public void Remove(Form g)

    var toRemove = g.Controls.OfType<Button>().Where(x => x.Name != "btn_reset").ToList();
    foreach(Button b in toRemove)
    
        g.Controls.Remove(b);
    

请注意:

您必须创建一个新的控件列表(示例中为toRemove),因为您不能直接遍历Controls 并从该列表中删除项目。 您必须添加using System.Linq;

更新: 正如其他用户所说, dispose 还会从其父级中删除控件。所以实际的问题不是调用Dispose,而是你使用迭代器的方式。所以你也可以使用这段代码

public void Remove(Form g)

    var toRemove = g.Controls.OfType<Button>().Where(x => x.Name != "btn_reset").ToList();
    foreach(Button b in toRemove)
    
        b.Dispose();
    

【讨论】:

g.Controls 中删除每个b 后,您不应该也调用b.Dispose() 吗?

以上是关于C# 销毁类的效果的主要内容,如果未能解决你的问题,请参考以下文章

Vue项目使用particles.js粒子效果以及销毁

DelegatingFilterProxy类的作用

线程池内的线程是否需要销毁?

C# 做3D效果

JSON C# Class Generator ---由json字符串生成C#实体类的工具

c#翻页效果