VBA: Разница в двух способах объявления нового объекта? (Пытаясь понять, почему мое решение работает)

Он отлично работает оракул

merge into table1 t1
using (select * from table2) t2
on (t1.empid = t2.empid)
when matched then update set t1.salary = t2.salary
30
задан Matt 19 March 2010 в 14:40
поделиться

2 ответа

В ответе Финка правильно описана ваша основная проблема, которая заключается в том, что ваш первый цикл добавляет несколько ссылок на один и тот же экземпляр 'clsMatch' в вашу коллекцию. Я просто расскажу подробнее, почему ваше исправление работает.

В VBA строка типа:

Dim c As New Collection

на самом деле не создает новую коллекцию. Оператор 'Dim' всегда является просто объявлением. Думайте о форме 'As New' как о сокращении для этого:

Dim c As Collection
'...

'(later, when you're about to use 'c')

If c Is Nothing Then
    Set c = New Collection
End If

'...

Вот почему уничтожение вашей ссылки путем установки содержащей ее переменной в 'Nothing' сработало. [ПРИМЕЧАНИЕ: тому, кто отредактировал этот вопрос, чтобы сказать "не работал" - это меняет смысл ответа и делает его неправильным. Пожалуйста, прочитайте исходный вопрос. ОП обнаружил, что установка переменной в "Nothing" сработала, а я объяснял почему это так]. Когда цикл возвращался к строке 'oMatch.setLineNumber', VBA "услужливо" создавал новый экземпляр 'clsMatch' для вашей переменной 'oMatch', на которую она должна была ссылаться, и тогда вы получали несколько различных экземпляров в вашей коллекции.

Возможно, было бы лучше сделать это явно:

Dim oMatch As clsMatch   

For i = 0 To 10                
    Set oMatch = New clsMatch                
    oMatch.setLineNumber i                
    oCollection.Add oMatch                
Next  

Обратите внимание, что (в отличие от C/C++ или ?NET) не имеет значения, где находится объявление 'Dim'. Оно не "выполняется" несколько раз внутри цикла, и область применения того, что оно объявляет, является процедурной, даже если оно появляется внутри цикла.

33
ответ дан 28 November 2019 в 00:06
поделиться

Когда вы добавляете объект oMatch в коллекцию, он передает переменную по ссылке на память. Когда вы снова объявляете oMatch как новый clsMatch, он не уничтожает указатель локальной памяти первого объекта, который вы создали. Он просто отдает вам ту же локальную область памяти, что и первый объект oMatch, который вы создали, даже если вы объявили его как новый объект. VBA использует ByRef в качестве техники передачи памяти по умолчанию. Затем места памяти коллекции обновляются, оба указывают на одно и то же место памяти с обновленным номером строки. Таким образом, все указатели памяти коллекции будут указывать на один и тот же последний созданный вами объект.

Когда вы устанавливаете oMatch = nothing, то сбрасывается указатель локальной памяти, создается новый объект oMatch с новым указателем локальной памяти, и все указатели коллекции будут указывать на свои правильные объекты.

По умолчанию в VBA передача памяти осуществляется по ByRef, в отличие от VB, где по умолчанию используется ByVal, поэтому вы можете столкнуться с этой оговоркой время от времени.

9
ответ дан 28 November 2019 в 00:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: