Переменная объекта не является объектом: это программная конструкция, которую мы используем для сохранения ссылки на единицу - фактический объект живет не в нашем коде, а в контексте времени выполнения VBA.
Dim objRef1 As Object
Set objRef1 = New Collection
Debug.Print ObjPtr(objRef1)
Dim objRef2 As Object
Set objRef2 = objRef1
Debug.Print ObjPtr(objRef2)
Это должно вывести один и тот же адрес дважды: обе переменные указывают на один и тот же объект: изменение свойств этого объекта одним ...
objRef1.Add 42
... повлияет на тот же объект, на который указывает другой:
Debug.Print objRef2.Count ' prints 1 even though .Add was called against objRef1
Передача объекта ByRef
(это неявное значение по умолчанию) означает, что вы передаете ссылку указателю объекта, поэтому его можно упростить до , передав сам указатель : параметр ByRef
теперь является локальной переменной в своей локальной области видимости, указывая на объект, на который также ссылается вызывающий объект.
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.
Передача объекта ByVal
означает, что вы передаете копию ссылки на указатель объекта - это отдельная ссылка на тот же объект :
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
.
И это именно то, что происходит с PersonModel
: его передача ByVal
дает вам локальную копию указателя объекта, указывающего на тот же объект, что и вызывающий код - ByVal
не выполняет глубокое клонирование целые объекты, он просто делает новую ссылку на тот же вовлеченный объект. Следовательно, изменение свойств этого объекта влияет на один и тот же объект независимо от того, передан ли указатель на этот объект по значению или по ссылке.