byref和byval其实按照字面上的理解来说,一个按照地址传递或者说指针,一个按照值传递,两个区别是什么呢,大众理解就是,按地址理解就是直接把它地址传进来,对形参的操作将影响实参。而按值传递就是copy实参的值放到另一块内存地址上,也就是要开辟内存,这两者的区别,确实,这样的说法对于使用值类型来说没有毛病,但是假如对于引用类型来说呢?且看我先给大家看的两个测试:
Module Module1
Public Class Test
Public Property Tag As String
Public Property name As String
End Class
''值类型按值传递
Public Sub ValTypeByval(ByVal valobj As Integer)
valobj = 20
End Sub
'值类型按地址传递
Public Sub ValTypeByref(ByRef valobj As Integer)
valobj = 20
End Sub
'引用类型按值传递
Public Sub RefTypeByval(ByVal refobj As Test)
refobj.Tag = "修改对象的属性"
End Sub
'引用类型按地址传递
Public Sub RefTypeByRef(ByRef refobj As Test)
refobj.Tag = "修改对象的属性"
End Sub
Sub Main()
Dim temptest As New Test '声明一个临时引用对象
Dim tempval As Integer = 10 '声明一个临时的值对象
temptest.Tag = "源对象的属性值"
temptest.name = "源对象"
ValTypeByval(tempval)
Console.WriteLine("值类型tempval按值传递后的值:{0}", tempval)
ValTypeByref(tempval)
Console.WriteLine("值类型tempval按地址传递后的值{0}", tempval)
RefTypeByval(temptest)
Console.WriteLine("引用类型temptest按值传递后的Tag属性:{0}", temptest.Tag)
temptest.Tag = "源对象的属性值" '重置值
RefTypeByRef(temptest)
Console.WriteLine("引用类型temptest按引用传递后的Tag属性:{0}", temptest.Tag)
Console.ReadKey()
End Sub
End Module
以上的代码都是在过程内部对形参进行修改,测试结果如下:
有点不对劲哦,看值类型的似乎按照着我们预料的路线在走,可是引用类型的,无论是按值传递或是按引用地址传递,都会被修改tag属性的值,这样是不是能得出对于引用类型而言,按值传递和按引用传递没有区别这个结论呢?
在仅做此测试时,我之前也是这么理解的,实际上不然,本质上还是有区别的,且看修改后的代码。
Public Sub RefTypeByval(ByVal refobj As Test)
Dim newrefobj As New Test
newrefobj.Tag = "值传递后的新对象"
refobj = newrefobj
End Sub
Public Sub RefTypeByRef(ByRef refobj As Test)
Dim newrefobj As New Test
newrefobj.Tag = "地址传递后的新对象"
refobj = newrefobj
End Sub
此次仅修改这两个过程的代码,先不解释,看结果
此次没有在过程内对形参的tag属性进行赋值,我们使用的是在过程内部创建新的对象,然后将新对象赋给形参,得到的结果可以看出,byval和byref是不是有区别了,所以上面得到的结论是错的,为什么会得到一个错误的结论呢?
首先我们在Dim obj as new test时,这个引用对象,实际上我们变量储存的只是它的地址,或者说指针吧。那么无论是byref或者byval时,我使用的形参的地址(byref 是直接引用变量,byva创建新的变量内存空间复制前变量的值即储存的内存地址)都是一样的,所以在给形参引用对象属性赋值时都可以修改。但是,变量的内存地址不等同于它储存的内存地址是吧。那么在refobj=new test时,byref修改的是实参的引用了。
变量o—>内存地址(储存的值为引用对象的内存地址)。所以byref只能修改的是一级指针,对于二级指针引用对象的地址我们没法修改。