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<Button>().Where(x => 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<>
)中,迭代正在修改的集合会引发异常 - 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# 销毁类的效果的主要内容,如果未能解决你的问题,请参考以下文章