我已经创建了一个函数来对表单中的所有控件进行迭代,以检查控件名称是否与字符串匹配。如果是,我想将控件本身作为对象返回,作为传递给程序其余部分的函数值。
这是我的工作:
Public Function getcontrolType(Optional ByVal controlString As String = "", Optional ByVal parentCtrl As Control = Nothing) As System.Object
Dim returnValue As System.Object
If parentCtrl Is Nothing Then
parentCtrl = MainModelForm
End If
For Each ctrl As Control In parentCtrl.Controls
If ctrl.HasChildren Then
getcontrolType(controlString, ctrl)
End If
If ctrl.Name = controlString Then
returnValue = ctrl.Name
Return returnValue
End If
Next
Return "Can't find control!"
End Function
我遇到的问题是程序正确执行到将returnValue赋值给ctrl.Name,然后执行Return语句然后转到End Function。但是,从那里开始,代码实际上并没有退出函数,而是跳回到getcontrolType(controlString,ctrl)行。我确信我的迭代必须有一些东西(计算机只有你告诉它们的那么聪明!),但我不明白为什么它会转到End Function行然后跳转回到代码?
感谢您的帮助!
答案 0 :(得分:2)
我不明白为什么它会转到End Function行然后 跳回代码?
这是可以预料的。当函数返回时,执行返回到前一个堆栈帧并从它离开的位置继续。这正是您的代码所做的。
令人困惑的部分来自于你的函数是递归的这一事实。您的印象是代码只是从Return
语句行移回到代码中的给定位置,类似于GOTO
操作。但事实是,堆栈确实会向下移动一帧,然后回到完成之前对同一函数的调用。
如果要查看此内容,只需在调试模式下运行代码并观察returnValue
变量的值。在代码“跳回”之后,您将看到它将指向不同的值。这是因为执行现在又回到完成父调用,其值已保存在内存中。
事实上,最后一部分实际上是你在进行递归调用时要非常小心的一个原因。他们越深入,他们需要的内存就越多。你可以在这里阅读:
Recursive Procedures (Visual Basic) - MSDN
从为什么您的实际代码无法按照您希望的方式工作,看起来您似乎永远不会使用嵌套调用getcontrolType
函数的返回值。将该部分更改为:
If ctrl.HasChildren Then
Return getcontrolType(controlString, ctrl)
End If
如果可以,我还建议您将函数的名称更改为GetControlName
,并使用System.String
作为返回类型。
或者更好的是:将其命名为GetControl
并让它返回找到的控件的实例(返回类型为System.Windows.Forms.Control
)。
修改强>
您是否了解ControlCollection.Find方法?它可能会更有效地为您提供您想要的东西:
Dim controlToFind = parentControl.Controls.Find("myControlName", True).SingleOrDefault();