Question

I've made a function to do an iteration on all the controls in a form to check if a control name matches with a string. If it does, I would like to return the control itself as an object as the function value that is passed to the rest of the program.

Here's my work:

 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

The issue I'm running into is that the program executes correctly to the point of assigning the returnValue to the ctrl.Name, and then it executes the Return statement and then goes to the End Function. From there though, the code doesn't actually exit the function and instead jumps back to the getcontrolType(controlString, ctrl) line. I'm sure there has to be something off with my iteration (computers are only as smart as you tell them to be!), but I don't understand why it would go to the End Function line and then jump back into the code?

Thanks for any and all help!

Was it helpful?

Solution

I don't understand why it would go to the End Function line and then jump back into the code?

This is to be expected. When a function returns, the execution goes back to the previous stack frame and resumes from where it left. This is exactly what your code does.

The confusing part comes from the fact that your function is recursive. You are under the impression that the code simply moves from the Return statement line back into a given position within code, similar to a GOTO operation. But truth is that the stack does in fact go down one frame, back to completing the previous call to the same function.

If you want to check this out, simply run your code in debug mode and watch the value of the returnValue variable. Right after the code "jumps back", you'll see that it will be pointing to a different value. This is because the execution is now back to completing the parent call, for which the value has been kept in memory.

In fact, that last part is actually one reason why you'd want to be very careful when making recursive calls. The deeper they go, the more memory they require. You can read about it here:

Recursive Procedures (Visual Basic) - MSDN

As of why your actual code doesn't work the way you want, it looks like you never use the returned value of the nested call to getcontrolType function. Change that part to this instead:

If ctrl.HasChildren Then
    Return getcontrolType(controlString, ctrl)
End If

If I may, I would also suggest that you change your function's name to GetControlName and use System.String as the return type.

Or better yet: name it GetControl and have it return the instance of the found control (with return type being System.Windows.Forms.Control).

EDIT:

Are you aware of the ControlCollection.Find method? It might give you what you want much more efficiently:

Dim controlToFind = parentControl.Controls.Find("myControlName", True).SingleOrDefault();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top