作为参数传递的对象 ByVal 应该如何表现 [英] How object passed as an argument ByVal should behave

查看:47
本文介绍了作为参数传递的对象 ByVal 应该如何表现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究/学习 ByVal 和 ByRef 在处理调用对象时的行为.所以我创建了这个类 PersonModel

I am studying/learning the bahavior of ByVal and ByRef when it comed to working with a call object. So I created this class PersonModel

Private Type TPerson
    firstName As String
    lastName As String
End Type

Private this As TPerson

Public Property Get firstName() As String
    firstName = this.firstName
End Property

Public Property Let firstName(ByVal strNewValue As String)
    this.firstName = strNewValue
End Property

Public Property Get lastName() As String
    lastName = this.lastName
End Property

Public Property Let lastName(ByVal strNewValue As String)
    this.lastName = strNewValue
End Property

Public Property Get fullName() As String
    fullName = this.firstName & " " & this.lastName
End Property

并且我制作了一个标准模块,试图查看在 s 子例程中作为 ByVal 或 ByRef 传递的对象的值如何受到影响.这是标准模块中的代码

And I made a standard module trying to see how the value of an object be affected if it's passed as ByVal or ByRef in s subroutine. Here's the code in standard module

Private passedPerson As PersonModel

Public Sub StructureType()
    Dim Object1 As PersonModel
    Dim Object2 As PersonModel

    Set Object1 = New PersonModel
    With Object1
        .firstName = "Max"
        .lastName = "Weber"
        Debug.Print .fullName 'gives Max Weber
    End With

    Set Object2 = Object1   'Object2 references Object1

    Debug.Print Object2.fullName 'gives Max Weber

    passByVal Object1
    ' First Call
    Debug.Print passedPerson.fullName  'gives Max Weber

    With Object2
        .firstName = "Karl"
        .lastName = "Marx"
        Debug.Print .fullName  'gives Karl Marx
    End With

    'Second Call
    Debug.Print passedPerson.fullName 'gives Karl Marx

End Sub

Private Sub passByVal(ByVal person As PersonModel)
    Set passedPerson = New PersonModel
    Set passedPerson = person
End Sub

我只是期望在代码的第二个调用部分 Debug.PrintpassedPerson.fullName 会给我一个不变的Max Weber"值.但相反,它赋予了新的价值卡尔·马克思".即使我将过程 passByVal 的代码更改为:

I was just expecting that in the second call part of the code Debug.Print passedPerson.fullName will give me an unchanged value of "Max Weber". But instead, it's giving the new value "Karl Marx". Even if I change the code of the procedure passByVal to:

Private Sub passByVal(ByVal person As PersonModel)
    Dim newPerson As PersonModel
    Set newPerson = New PersonModel
    Set newPerson = person

    Set passedPerson = newPerson
End Sub

第二次调用部分代码 Debug.PrintpassedPerson.fullName 仍然给出Karl Marx".无论将 ByVal 更改为 ByRef,它仍然给出相同的结果.

Second call part of the code Debug.Print passedPerson.fullName is still giving "Karl Marx". Regardless of changing ByVal to ByRef, it's still giving the same result.

我有两个问题:1.这真的应该如何工作吗?2. 如果我的目标是将变量 passedPerson 的值保持为Max Weber",我做错了什么?

I have two questions: 1. Is this how it should really work? 2. What am I doing wrong if my aim is to keep the value of the variable passedPerson to "Max Weber"?

推荐答案

对象变量不是对象:它是一种编程结构,我们用来保持对一个引用 - 实际对象不存在于我们的代码中,而是存在于 VBA 运行时上下文中.

An object variable isn't an object: it's a programming construct that we use to keep a reference to one - the actual object lives not in our code, but in the VBA runtime context.

Dim objRef1 As Object
Set objRef1 = New Collection
Debug.Print ObjPtr(objRef1)

Dim objRef2 As Object
Set objRef2 = objRef1
Debug.Print ObjPtr(objRef2)

这应该输出相同的地址,两次:两个变量都指向同一个对象:用一个更改该对象的属性...

This should output the same address, twice: both variables are pointing to the same object: changing the properties of that object with one...

objRef1.Add 42

...将影响另一个也指向的对象:

...will affect the very same object that the other also points to:

Debug.Print objRef2.Count ' prints 1 even though .Add was called against objRef1

<小时>

传递对象ByRef(这是隐式默认值)意味着您将引用传递给对象指针,因此它可以简化为传递指针本身:ByRef 参数现在是其自身局部作用域中的局部变量,指向调用者也有引用的对象.


Passing an object ByRef (it's the implicit default) means you're passing a reference to the object pointer, so it can be simplified to passing the pointer itself: the ByRef parameter is now a local variable in its own local scope, pointing to an object to which the caller also has a reference.

Public Sub CallingCode()
    Dim objRef1 As Object
    Set objRef1 = New Collection
    PassByReference objRef1
    Debug.Print objRef1.Count ' error 91, the object reference is gone!
End Sub

Private Sub PassByReference(ByRef thing As Object)
    thing.Add 42
    Set thing = Nothing
End Sub

因为引用正在被传递,在任一过程中将其设置为Nothing将使该对象的引用计数为0,并且该对象被销毁.这里对象被销毁,然后被访问,这会引发错误 91.

Because the reference is being passed, setting it to Nothing in either procedure will bring that object's reference count to 0, and the object gets destroyed. Here the object is destroyed and then accessed, which raises error 91.

传递对象 ByVal 意味着您将引用的副本传递给对象指针 - 它是对同一个对象的不同引用强>:

Passing an object ByVal means you're passing a copy of the reference to the object pointer - it's a distinct reference to the very same object:

Public Sub CallingCode()
    Dim objRef1 As Object
    Set objRef1 = New Collection
    PassByValue objRef1
    Debug.Print objRef1.Count ' 1
End Sub

Private Sub PassByValue(ByVal thing As Object)
    thing.Add 42
    Set thing = Nothing
End Sub

这里的本地副本被设置为Nothing,但由于调用代码也有对该对象的引用,对象本身并没有被破坏——所以元素 42 被添加到集合中,Debug.Print 输出 1.

Here the local copy is being set to Nothing, but since the calling code also has a reference to that object, the object itself isn't getting destroyed - so the element 42 was added to the collection, and Debug.Print outputs 1.

这正是你的 PersonModel 发生的事情:传递它 ByVal 会给你一个对象指针的本地副本,指向与调用代码完全相同的对象- ByVal 不会深度克隆整个对象,它只是对同一个涉及的对象进行新的引用.因此,无论指向该对象的指针是按值传递还是按引用传递,修改该对象的属性都会影响完全相同的对象.

And that's exactly what's going on with your PersonModel: passing it ByVal gives you a local copy of the object pointer, pointing to the exact same object as the calling code - ByVal doesn't deep-clone entire objects, it simply makes a new reference to the same involved object. Hence, modifying that object's properties affects the exact same object regardless of whether the pointer to that object is passed by value or by reference.

这篇关于作为参数传递的对象 ByVal 应该如何表现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆