:
: hey all,
:
: i have the following 2 classes:
:
:
: Public Class DataAccessLayer
: ...
: ...
: Public Sub GetRecords(ByRef ds As DataSet1)
: ds = New DataSet1
: Me.SqlDataAdapter1.Fill(ds)
: End Sub
: End Class
:
:
: Here's the class that uses the above class:
:
: Public Class Class1
: Public Function GetCustomers() As DataSet1
: Dim ds As DataSet1
: Dim dal As New DataAccessLayer
: dal.GetRecords(ds)
: Return ds
: End Function
: End Class
:
: in the DataAccessLayer class, i thought using byref or byvalue doesn't
: make a difference since the parameter is a reference variable. am i
: nuts?
:
: thanks,
: ari
ByRef means that any changes to the underlying variable you are passing into
the function will be visible when the function exists. ByVal in turn means
any such changes are discarded. The key is to understanding exactly what it
is you are passing in as a parameter.
In this case, you are passing in a reference value - that is, a pointer to
an object on the heap. If you pass it in ByRef, the specific instance of
the object type that the pointer is referencing can be changed when the
function exits. If you pass it in ByVal however, any such changes are
discarded. Either way, any changes to the instance of the object itself are
visible after the function exits.
Consider a simple example:
'--------------------------------------------------------
Public Class TestClass
Public n As Integer = 0
End Class
Public Module [module]
Private Sub SubOne(ByRef TCls As TestClass)
TCls = New TestClass
TCls.n = 10
End Sub
Private Sub SubTwo(ByVal TCls As TestClass)
TCls = New TestClass
TCls.n = 10
End Sub
Public Sub Main()
Dim TClsOne As TestClass
Dim TClsTwo As TestClass
TClsOne = New TestClass
TClsTwo = TClsOne
TClsOne.n = 1
Console.WriteLine("Original object values: ")
Console.WriteLine("TClsOne: " & TClsOne.n)
Console.WriteLine("TClsTwo: " & TClsTwo.n)
Console.WriteLine
SubOne(TClsOne)
SubTwo(TClsTwo)
Console.WriteLine("Object values after calling subs: ")
Console.WriteLine("TClsOne: " & TClsOne.n)
Console.WriteLine("TClsTwo: " & TClsTwo.n)
End Sub
End Module
'--------------------------------------------------------
Here we have a simple class with a single Public Integer member. Our module
in turn creates two references to the same object:
'--------------------------------------------------------
Dim TClsOne As TestClass
Dim TClsTwo As TestClass
TClsOne = New TestClass
TClsTwo = TClsOne
TClsOne.n = 1
'--------------------------------------------------------
While we've defined two object references, we actually only create a single
instance of the object. Both references variables TClsOne and TClsTwo in
fact point to the same instance of the TestClass object. A change to the
member variable 'n' by the first reference is therefore reflected in the 2nd
reference. When we output the first section we see the following:
'--------------------------------------------------------
Original object values:
TClsOne: 1
TClsTwo: 1
'--------------------------------------------------------
Note that the change to the value of TClsOne.n is seen in the reference to
TClsTwo.n - again these two reference variable are pointing to the same
object instance in memory.
Now let's consider what is happening when we call our two subs (which differ
only by the fact that one parameter is passed in ByRef and the other is
passed in ByVal):
'--------------------------------------------------------
Private Sub SubOne(ByRef TCls As TestClass)
TCls = New TestClass
TCls.n = 10
End Sub
Private Sub SubTwo(ByVal TCls As TestClass)
TCls = New TestClass
TCls.n = 10
End Sub
[...]
SubOne(TClsOne)
SubTwo(TClsTwo)
[...]
'--------------------------------------------------------
In both cases a brand new instance of the TestClass object is create on the
heap and the reference variable is changed to point to it. We then change
the value of 'n' for that new object and exit. However, when we print out
the second output section, we see a different result:
'--------------------------------------------------------
Object values after calling subs:
TClsOne: 10
TClsTwo: 1
'--------------------------------------------------------
Note that now the value of TClsOne.n is set to '10' whereas the value of
TClsTwo.n remains '1'. This is because in SubOne(), the TCls parameter is
passed in ByRef. Therefore, when we created the new TestClass object inside
the sub and set the TCls variable to point to it, that assignment remained
in place when the sub exited. At that point, TClsOne is pointing to the 2nd
instance of the TestClass object while TClsTwo is still pointing to the
original reference.
When we call SubTwo, the same steps occur inside the procedure. This time
however, the new reference is discarded when SubTwo exits and TClsTwo
therefore still points to the original object instance that it did prior to
calling the sub.
To summarize, the ByRef/ByVal keywords are relevant to both Value types and
Reference types. In the case of the Reference type, what you are passing in
is a pointer to an object (hence the term 'Reference' type). If you change
the instance that the parameter is pointing to, that reassignment is
retained when the Sub/Function exits if the parameter is passed in ByRef and
discarded if the parameter is passed in ByVal.
HTH.
Ralf