E
eBob.com
I guess I have fallen into the habit of generally passing values ByRef,
unless I am certain that the method will never need to alter the value.
Also I have never been quite sure what it means to pass a reference type
ByVal. And I have never had a problem. Until this past weekend.
This past weekend I was playing around with a TreeView representation of a
directory and developed the code attached below. The code is very
straightforward. A button click routine establishes the topmost node and
then calls a recursive subroutine, Populate, to populate the rest of the
tree. The second argument to Populate is a TreeNode and I had that being
passed ByRef, because a TreeNode is a reference type, and, as I said, I am
not sure what it means to pass a reference type ByVal. And besides it has
always worked for me to pass practically everything ByRef.
The result was that the topmost node was duplicated!
I had no clue what was going on, and so, after a lot of head scratching and
searches, I posted a message here which for some reason never appeared. But
a subsequent update to my original note did appear in at least the easynews
copy of this ng but not here (here being the microsoft maintained copy of
the ng). And Captain Jack kindly informed me that the problem was that I
was passing the TreeNode parameter ByRef and he is certainly right.
BUT ... it seems to me that the parameter should be passed ByRef. The
Populate function is going to be hanging subnodes off the passed topmost
node. And my basic understanding of ByRef is that that is the way to pass
something which the subroutine/function might change.
So, please, why does the second argument to my Populate function have to be
passed ByVal?
Also, since my searches have only confirmed that I am not the only person
confused by this, what does it mean to pass a reference type ByVal? Some
Internet posts say that the only difference is that you are passing a copy
of the pointer rather than the pointer itself. But I tried this dirt simple
little experiment ...
Public Class Form1
Dim astring As String = "abc"
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
touchitbyval(astring)
MsgBox(astring)
End Sub
Sub touchitbyval(ByVal somestring As String)
somestring = "xyz"
End Sub
End Class
.... and the value of astring is not changed! That makes me think that maybe
a clone, of the object, not the reference, is being passed, which would be
consistent with what it means to pass a value type ByVal, but is not what
many Internet posts say. And if a clone is being passed in my TreeView
program, the one attached below, then I do not see how my Populate function
is able to hang additional nodes off it.
If one of you gurus here who REALLY understand this stuff could provide an
authoritative explanation I would appreciate it, and you would be making a
real contribution to the community as I am certainly not the only one who is
confused.
Thanks, Bob
Option Strict On
Option Explicit On
Imports System.IO
Public Class Form1
Enum PopRtnCode
OK 'OK
uae 'UnauthorizedAccessException
miscerror 'some error other than above
End Enum
Private Sub btnBuildTree_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnBuildTree.Click
If Not Directory.Exists(tbxTopDir.Text) Then
Else
Dim basenode As New TreeNode(tbxTopDir.Text)
tvDir.Nodes.Add(basenode)
Dim tag As String
Select Case Populate(tbxTopDir.Text, tvDir.Nodes(0))
Case PopRtnCode.OK
tag = ""
Case PopRtnCode.uae
tag = " <Access Exception>"
Case PopRtnCode.miscerror
tag = " <Misc. Error>"
End Select
tvDir.Nodes(0).Text = tbxTopDir.Text & tag
End If
End Sub
Function Populate(ByRef directoryValue As String, ByVal parentNode As
TreeNode) _
As PopRtnCode 'pass 2nd arg ByRef to demonstrate problem
tbxDebug.AppendText("called for directory: """ & directoryValue & _
""" / parentnode: " & parentNode.ToString &
vbCrLf)
'depth += 1
Dim directoryArray() As String
Try
directoryArray = Directory.GetDirectories(directoryValue)
Catch ex As UnauthorizedAccessException
Return PopRtnCode.uae
Catch ex As Exception
Return PopRtnCode.miscerror
End Try
If (directoryArray.Length <> 0) Then
For Each directory As String In directoryArray
Dim substringDirectory As String
substringDirectory = directory.Substring( _
directory.LastIndexOf("\") + 1, _
directory.Length - directory.LastIndexOf("\") - 1)
tbxDebug.AppendText("substringDirectory is: " &
substringDirectory & vbCrLf)
Dim myNode As TreeNode = New TreeNode(substringDirectory)
parentNode.Nodes.Add(myNode)
myNode.Expand()
Application.DoEvents()
'MsgBox("pace")
Dim tag As String = ""
Select Case Populate(directory, myNode)
Case PopRtnCode.OK
tag = ""
Case PopRtnCode.uae
tag = " <Access Exception>"
Case PopRtnCode.miscerror
tag = " <Misc. Error>"
End Select
myNode.Text = substringDirectory & tag
Next
End If
tbxDebug.AppendText("returning from handling directory: " &
directoryValue & vbCrLf)
'MsgBox("returning from handling directory: " & directoryValue)
End Function ' Populate
End Class
unless I am certain that the method will never need to alter the value.
Also I have never been quite sure what it means to pass a reference type
ByVal. And I have never had a problem. Until this past weekend.
This past weekend I was playing around with a TreeView representation of a
directory and developed the code attached below. The code is very
straightforward. A button click routine establishes the topmost node and
then calls a recursive subroutine, Populate, to populate the rest of the
tree. The second argument to Populate is a TreeNode and I had that being
passed ByRef, because a TreeNode is a reference type, and, as I said, I am
not sure what it means to pass a reference type ByVal. And besides it has
always worked for me to pass practically everything ByRef.
The result was that the topmost node was duplicated!
I had no clue what was going on, and so, after a lot of head scratching and
searches, I posted a message here which for some reason never appeared. But
a subsequent update to my original note did appear in at least the easynews
copy of this ng but not here (here being the microsoft maintained copy of
the ng). And Captain Jack kindly informed me that the problem was that I
was passing the TreeNode parameter ByRef and he is certainly right.
BUT ... it seems to me that the parameter should be passed ByRef. The
Populate function is going to be hanging subnodes off the passed topmost
node. And my basic understanding of ByRef is that that is the way to pass
something which the subroutine/function might change.
So, please, why does the second argument to my Populate function have to be
passed ByVal?
Also, since my searches have only confirmed that I am not the only person
confused by this, what does it mean to pass a reference type ByVal? Some
Internet posts say that the only difference is that you are passing a copy
of the pointer rather than the pointer itself. But I tried this dirt simple
little experiment ...
Public Class Form1
Dim astring As String = "abc"
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
touchitbyval(astring)
MsgBox(astring)
End Sub
Sub touchitbyval(ByVal somestring As String)
somestring = "xyz"
End Sub
End Class
.... and the value of astring is not changed! That makes me think that maybe
a clone, of the object, not the reference, is being passed, which would be
consistent with what it means to pass a value type ByVal, but is not what
many Internet posts say. And if a clone is being passed in my TreeView
program, the one attached below, then I do not see how my Populate function
is able to hang additional nodes off it.
If one of you gurus here who REALLY understand this stuff could provide an
authoritative explanation I would appreciate it, and you would be making a
real contribution to the community as I am certainly not the only one who is
confused.
Thanks, Bob
Option Strict On
Option Explicit On
Imports System.IO
Public Class Form1
Enum PopRtnCode
OK 'OK
uae 'UnauthorizedAccessException
miscerror 'some error other than above
End Enum
Private Sub btnBuildTree_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnBuildTree.Click
If Not Directory.Exists(tbxTopDir.Text) Then
Else
Dim basenode As New TreeNode(tbxTopDir.Text)
tvDir.Nodes.Add(basenode)
Dim tag As String
Select Case Populate(tbxTopDir.Text, tvDir.Nodes(0))
Case PopRtnCode.OK
tag = ""
Case PopRtnCode.uae
tag = " <Access Exception>"
Case PopRtnCode.miscerror
tag = " <Misc. Error>"
End Select
tvDir.Nodes(0).Text = tbxTopDir.Text & tag
End If
End Sub
Function Populate(ByRef directoryValue As String, ByVal parentNode As
TreeNode) _
As PopRtnCode 'pass 2nd arg ByRef to demonstrate problem
tbxDebug.AppendText("called for directory: """ & directoryValue & _
""" / parentnode: " & parentNode.ToString &
vbCrLf)
'depth += 1
Dim directoryArray() As String
Try
directoryArray = Directory.GetDirectories(directoryValue)
Catch ex As UnauthorizedAccessException
Return PopRtnCode.uae
Catch ex As Exception
Return PopRtnCode.miscerror
End Try
If (directoryArray.Length <> 0) Then
For Each directory As String In directoryArray
Dim substringDirectory As String
substringDirectory = directory.Substring( _
directory.LastIndexOf("\") + 1, _
directory.Length - directory.LastIndexOf("\") - 1)
tbxDebug.AppendText("substringDirectory is: " &
substringDirectory & vbCrLf)
Dim myNode As TreeNode = New TreeNode(substringDirectory)
parentNode.Nodes.Add(myNode)
myNode.Expand()
Application.DoEvents()
'MsgBox("pace")
Dim tag As String = ""
Select Case Populate(directory, myNode)
Case PopRtnCode.OK
tag = ""
Case PopRtnCode.uae
tag = " <Access Exception>"
Case PopRtnCode.miscerror
tag = " <Misc. Error>"
End Select
myNode.Text = substringDirectory & tag
Next
End If
tbxDebug.AppendText("returning from handling directory: " &
directoryValue & vbCrLf)
'MsgBox("returning from handling directory: " & directoryValue)
End Function ' Populate
End Class