Должен ли я сбросить переменную объекта VBA или закрыть установленный объект, а затем установить новую переменную? - PullRequest
0 голосов
/ 04 мая 2018

Для программы VBA, которая использует одну и ту же переменную объекта несколько раз, лучше всего сбросить переменную в цикле без предварительной установки переменной на ничего (что можно сделать в конце вне цикла), или если Переменная всегда должна быть нулевой после каждого случая использования. С точки зрения подсчета ссылок, кажется, лучше всего ничего не устанавливать, так как мне никогда не нужно предыдущее состояние объекта после его изменения на следующую переменную (я не уверен, как можно получить предыдущее состояние, но я понимаю, что должна быть функция такого из этого вопроса ). Другой важный вопрос, который я рассмотрел, можно найти здесь .

Приложение, которое вызвало этот вопрос, - это приложение, в котором я перебираю множество документов Word, извлекая соответствующую информацию из каждого из них. Смотрите пример ниже:

dim objDoc as object, objWord as object
Set objWord = CreateObject("Word.Application")
for r=2 to 40
    'Some code to set filename 
    Set objDoc = objWord.Documents.Open(filename, ReadOnly:=False, Visible:=False)
    'Code to retrieve relevant info from document
    objDoc.close
    Set objDoc = nothing 'Should this go here?
next r
set objDoc = nothing 'Or should it go here?
objWord.Quit

Вопрос : Имеет ли значение, когда вы устанавливаете переменную объекта в ничто с точки зрения эффективности кода или избежания проблем. Выше я выделил два варианта, которые, как я полагаю, должны идти с третьим вариантом, это то, что не имеет значения, когда я устанавливаю переменную в ничего

Ответы [ 3 ]

0 голосов
/ 04 мая 2018

Краткий ответ: в цикле.

Длинный ответ: С точки зрения избежания проблем, вы должны установить его на «ничего», когда вы сразу покончите с этим. Проблема, которую вы будете пытаться поймать, заключается в непреднамеренном повторном использовании. Вы хотите, чтобы ваш код взорвался, если вы когда-нибудь случайно использовали переменную вместо необходимости отлаживать ее позже, когда она дает странные результаты. Вообще говоря, вы не должны повторно использовать переменные, потому что слишком легко допустить ошибку при рефакторинге, и переменная в конечном итоге будет содержать неправильное значение.

VBA, к сожалению, не волнует, если вы используете переменную вне innerscope, в которой она была затемнена. К сожалению, следующие правила являются законными, и более современные языки не позволяют вам этого делать:

Sub CountInsideLoop()

    Dim i As Long
    For i = 1 To 3
        Dim count As Long
        count = count + 1
    Next i

    ' count value will be 3
    Debug.Print count
End Sub
0 голосов
/ 05 мая 2018

Внутри петли

Что следует легко вывести из следующего эквивалентного кода:

dim objWord as object
Set objWord = CreateObject("Word.Application")

for r=2 to 40
    'Some code to set filename 
    With objWord.Documents.Open(filename, ReadOnly:=False, Visible:=False) 'Set and reference your document object
        'Code to retrieve relevant info from document
        .Close
    End With 'this “disposes” the referenced document object, so you also set it to Nothing
Next r
objWord.Quit

Конечно, есть место для дальнейшего применения той же концепции и к objWord:

With CreateObject("Word.Application") ‘ instantiate and reference your Word object
    for r=2 to 40
        'Some code to set filename 
        With .Documents.Open(filename, ReadOnly:=False, Visible:=False) 'Set and reference your document object
            'Code to retrieve relevant info from document
            .Close
        End With 'this “disposes” the referenced document object, so you also set it to Nothing
    Next r
    .Quit
End With 'this “disposes” the referenced Word object, so you also set it to Nothing
0 голосов
/ 04 мая 2018

Я бы сказал, что, вообще говоря, наличие переменной, которая имеет два или более различных значения в зависимости от контекста, делает жизнь сопровождающего более сложной, чем она должна быть. В этом случае, независимо от того, помещаете ли вы его внутри или вне области видимости цикла , значение не должно иметь никакого значения вообще - фактически, если Set objDoc = Nothing указано вообще, должно также не иметь значения.

Вы не показываете остальную часть процедуры, но, насколько я понимаю, на самом деле нет причины, по которой эта конкретная процедура не будет выполнять 10 000 других операций.

Код, который вы показали , должен быть записан в связке процедур и функций.

'Some code to set filename 

Вам нужна функция, которая реализует логику для получения имени файла и возвращает String.

'Code to retrieve relevant info from document

Вам нужна процедура, которая извлекает соответствующую информацию из документа.

Потяните тело цикла в свою собственную процедуру:

For r = 2 To 40
    filename = LogicToGetTheFilename(r)
    ProcessWordDocument wordApp, filename
Next

Намного выше уровень абстракции здесь - при правильном названии вы знаете, что делает этот цикл с первого взгляда .

Private Sub ProcessWordDocument(ByVal wordApp As Object, ByVal filename As String)
    Dim docx As Object 'Word.Document
    Set docx = wordApp.Documents.Open(filename, ...)
    'do stuff
    docx.Close
    'Set docx = Nothing
End Sub

Теперь, когда переменная объекта документа Word находится в своей собственной области, VBA должен надлежащим образом уничтожить базовый объект всякий раз, когда выполнение выходит из этой области (то есть один раз за итерацию цикла).

Поскольку рефакторинг цикла в надлежащие уровни абстракции означает, что документ Word живет только одну итерацию, я бы сказал (довольно сильно), что Set objDoc = Nothing принадлежит внутри тела цикла.

...