【问题标题】:vb.net "For Each" iterates only once over a listvb.net “For Each” 仅在列表上迭代一次
【发布时间】:2013-05-17 04:55:27
【问题描述】:

下面的“for each”循环只运行一次。为什么?

该项目包含 4 个表单。 Form1 包含 4 个 PictureBox。我正在尝试遍历表单列表(在此示例中,将每个表单的 BG 设置为图片框):

Sub Butt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Butt.Click
    Dim Forms As New List(Of Form)
    Dim Pics As New Dictionary(Of Form, PictureBox)
    Forms.Add(me)
    Forms.Add(form2)
    Forms.Add(form3)
    Forms.Add(form4)

只执行第一次迭代:

    For Each frm As Form In Forms
        pics(frm) = Me.Controls("PictureBox" + CStr(i + 1))(0)
        'BTW the next line behave the same:
        '  pics(frm) = CType(Me.Controls("PictureBox" + CStr(i + 1)), PictureBox)
        'or this:
        '  pics(frm) = PictureBox1
        'or if the pics is a dictionary(of string):
        '  pics(frm.name) = PictureBox1
    Next

执行所有 4 次迭代:

    For Each frm As Form In Forms
        msgbox(frm.name)
    Next

为什么它不会在第一个循环中完成所有 4 次迭代?

编辑:

“i”不是问题。 显然问题在于将相同的控件分配两次,作为“图片”字典的值......仍在调查中。

编辑 2 - 中间摘要

可行的解决方案(但不是答案)

For x As Integer = 0 To Forms.Count - 1
    pics(Forms(x)) = DirectCast(PictureBox1, PictureBox)
Next

你的答案可以归类为

1。字典语法:dict.add(k, v) vs. dict(k) = v

2。正如一些人所建议的那样,exceotion 怪物吃掉了我的异常。

3。正如@Andre Pageot 所建议的那样,需要施放巫术

4。 VB 不喜欢将同一个图片框两次添加到字典中。

(1.) 可能不是问题所在。 dict(k) = v 语法适用于其他任何地方。我什至尝试了 dict.add(k,v) 并且它给出了完全相同的行为,即仍然错误。

(2.) IDE 确实有问题:调试器跳过“Next”语句,并照常继续循环后的下一条指令。 (世界跆拳道联盟) 即使在我设置为在 Alt+Ctrl+E 屏幕中捕获所有异常之后也没关系。 仍然没有捕获到异常。

恕我直言,这是一个严重的错误,即使 redmond 的某个人是故意设计的。同样的“有趣的行为”可能是从 VB6 时代继承下来的,有时代码会无缘无故地“飞走”。 (但至少在那里它正在退出应用程序)。

附言我没有任何“try-catch”子句,也没有“错误时做一些愚蠢的事情”,只是为了清楚:)

(3.) 可能是这样,虽然我不明白,但它没有回答问题 - “为什么原始代码在运行时执行 weewooo”。

参见上面的“工作解决方案”。

坦率地说,我不想再理解它了,因为它让我发疯,为什么,在 Python 中,我只写 dict(k) = y 并且它永远不会中断。我不明白 dict.contains(k,v) 是如何可能的。它没有任何意义。 并且必须有感觉,它是在编程,而不是巫术。

(4.) 我没有任何方法(或意愿)来证明这一点。

谢谢你们。

在这个项目之后我可能再也不会使用 VB 了。有这么多巫毒的事情要处理,不值得头疼。

【问题讨论】:

  • i 是在哪里定义的,你要增加它吗?
  • 引用图片框后您没有增加i,这是一个错误还是您在其他地方增加了这个?
  • 为什么重要(关于问题,而不是逻辑)?我添加了一个没有“i”的(注释)示例。
  • 您是否在Next 上设置了一个断点以确保它到达那里?我的猜测是它在 for each 内部崩溃并且永远不会到达它一次。
  • 它可能会抛出一个被某个地方吞下的错误。单步执行代码以查看发生了什么。另外,您在字典中填充值的代码在哪里?

标签: vb.net


【解决方案1】:

因为这部分:

pics(frm)

大概是Nothing。我在这里猜测是因为我没有抛出异常。

您永远不会到达Next 语句。这就是为什么你只有一次迭代。
您的错误正在其他地方被吞没。尝试在 Exceptions 面板中激活 Common Language Runtime ExceptionsThrown 属性。 (ctrl + alt + e).


也许你应该尝试替换

pics(frm)

pics.Add(frm, Me.Controls("PictureBox" + CStr(i + 1))(0))

【讨论】:

  • 更有可能是Nothing,因为这是 VB.NET ;-)
  • 不幸的是,这个神秘的异常仍然没有被捕获,即使在设置了所有要处理的异常之后(即使我重新启动了 VS,只是为了确保)
  • @BerryTsakala ...也许你可以试试这个:pics.Add(frm, Me.Controls("PictureBox" + CStr(i + 1))(0))。这只是一种预感。
【解决方案2】:

我似乎记得遇到过类似的问题,如果记忆有用,诀窍是客观地从 for each like so 中删除表单

Sub Butt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles     Butt.Click
Dim Forms As New List(Of Form)
Dim Pics As New Dictionary(Of Form, PictureBox)
Forms.Add(me)
Forms.Add(form2)
Forms.Add(form3)
Forms.Add(form4)

For x As Integer = 0 To Forms.Count - 1
    If Not Pics.Contains(Forms(x), DirectCast(Me.Controls("PictureBox" + CStr(i + 1))(0), PictureBox)) Then
            Pics.Add(Forms(x), DirectCast(Me.Controls("PictureBox" + CStr(i + 1))(0), PictureBox))
        Else
            Pics(Forms(x)) = DirectCast(Me.Controls("PictureBox" + CStr(i + 1))(0), PictureBox)
        End If
Next

############################################ ############################################ 更新探索和扩展在上面############################################### ###############################

以下是对这个问题的更详细的解释和分解,以及为什么它实际上不是 .NET 中的神话或奇怪现象

.NET OO 框架非常庞大复杂且功能强大,要理解和记住这一切并非人类不可能,但需要掌握一些概念才能在迷宫中导航。

让我们检查一下出了什么问题。

您用项目中的每个表单声明并填充了表单列表List(Of Form)

Dim Forms as New List(Of Form)

然后您声明了一个字典来保存形状(Form、PictureBox)的(键、值)集合

Dim Pics as New Dictionary(Of Form, PictureBox)

这意味着你的“Key”是 Form 类型,而“Value”是 PictureBox 类型

现在,使用您正在遍历列表中每个表单的表单列表,说您想要“键”的“值”(PictureBox)(Form) 将 Dictionary*(Pics)* 中的 /em> 设置为在当前表单 (代码正在运行的地方) 上找到的 PictureBox,名称为“PictureBox(x)”,其中 x 是您的增量整数某种价值。奇怪的是,您随后要求该图片框的第一个实例(那是最后的 (0) 部分)

For Each frm As Form In Forms
    pics(frm) = Me.Controls("PictureBox" + CStr(i + 1))(0)
Next

从根本上说,从 pics(frm) 调用的方法仅获取或设置字典中现有项目的值,因为字典尚未加载任何内容,Pics 为空,您从未添加任何内容将表单添加到字典中,因此根本不会设置任何内容。

实现键值分配的更合适的方法如下,但是简单地设置表单的背景图像仍然是矫枉过正

Sub BuildDictionary()
    '1. Declare the array of forms and the dictionary of (Key,Values) of type (Form,PictureBox)
    Dim Forms As New List(Of Form) 'list of forms that you want to assign BG
    Dim Pics As New Dictionary(Of Form, PictureBox) 'declare your dictionary list ("Key","Value") = (Form,Picturebox)
    With Forms 'fill the list
        .Add(Me)
        .Add(Form1)
        .Add(Form2)
        .Add(Form3)
    End With

    '2. Snag the picturebox we want to assign to the forms
    Dim PictureBoxToAssign As PictureBox = DirectCast(Me.Controls("PictureBox" + CStr(i + 1)), PictureBox) 'grab your picturebox

    '3 option 1 (prefered)
    '#### Either Do this next
    Pics.Clear() 'if your logic allows that you can clear the dictionary first
    For x As Integer = 0 To Forms.Count - 1 'for each form in the array
        Pics.Add(Forms(x), PictureBoxToAssign) 'add the form and picturebox to the dictionary            
    Next

    '3 option 2 (only if you cannot clear the dictionary)
    '#### Or Do this
    'you cannot clear the dictionary first due to logic
    For x As Integer = 0 To Forms.Count - 1 'for each form in the array
        'check existance of the pair
        If Pics.Contains(New Generic.KeyValuePair(Of Form, PictureBox)(Forms(x), PictureBoxToAssign)) Then
            Pics(Forms(x)) = PictureBoxToAssign 'update the value 
        Else
            Pics.Add(Forms(x), PictureBoxToAssign) 'add the new pair
        End If
    Next
End Sub

如果目标只是将每个表单的背景图像设置为图片框的图像,那么可能更快更有效的路线可能是以下示例

Sub SetBG()
    Dim Forms As Form() = {Me, Form1, Form2, Form3} 'array of forms that you want to assign BG, occupies less memory than a list
    Dim PictureBoxToAssign As PictureBox = DirectCast(Me.Controls("PictureBox" + CStr(i + 1)), PictureBox) 'grab your picturebox
    For x As Integer = 0 To Forms.Count - 1 'for each form in the array
        Forms(x).BackgroundImage = PictureBoxToAssign.Image 'assign the image to the background      
    Next
End Sub

这里要记住的重要一点是,当以任何方式更改对象时,在遍历数组中的对象集合时,尽管可能,但不能使用“for each obj as输入对象数组”的方法,即不是这样的

For Each obj as ObjectType in ArrayofObjects
    Change the properties of obj = (BIG NO CAN DO)
Next

必须将循环与直接与集合中的对象交互分开,在本示例中,通过使用 for each 像这样的索引

For x As Integer = 0 To Forms.Count - 1 'using an integer not the object itself
    'referencing the object through the index of the collection Forms(x)
    Forms(x).BackgroundImage = PictureBoxToAssign.Image 
Next

我希望这个答案能给黑暗带来光明

【讨论】:

  • 我真的不明白这些,但它有点工作。请参阅我在原始问题中的最后一次编辑。
【解决方案3】:

分配给您的 Pics 词典的代码在我看来是错误的。要将新项目添加到字典中,您不能只分配给该索引。您必须使用 .Add() 方法。

当您尝试分配给尚不存在的键时,应引发异常。这可以通过您的循环解释一次。您第一次进入循环,抛出异常,因此您的代码永远不会到达第二次迭代。如果你在某个地方吞下了那个异常,你永远不会知道。

Sub Butt_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Butt.Click
    Dim Forms As New List(Of Form)
    Dim Pics As New Dictionary(Of Form, PictureBox)
    Forms.Add(me)
    Forms.Add(form2)
    Forms.Add(form3)
    Forms.Add(form4)

    For Each frm As Form In Forms
        pics.Add(frm, Me.Controls("PictureBox" + CStr(i + 1))(0))
    Next

【讨论】:

  • 什么意思?我一直这样做。根据 MSDN (msdn.microsoft.com/en-us/library/9tee9ht2.aspx),“集合操作使用指定的键创建一个新元素”。
  • downvote:在第二个循环中使用相同的语法,它确实有效。
猜你喜欢
  • 2015-05-21
  • 2021-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-17
  • 2015-06-02
  • 2021-10-02
相关资源
最近更新 更多