excel-vba
Лучшие практики VBA
Поиск…
замечания
Мы все знаем их, но эти практики гораздо менее очевидны для тех, кто начинает программировать в VBA.
ВСЕГДА Используйте «Option Explicit»
В окне редактора VBA в меню «Сервис» выберите «Параметры»:
Затем на вкладке «Редактор» убедитесь, что «Требовать переменную декларацию» отмечен:
При выборе этой опции автоматически добавляется Option Explicit
в верхней части каждого модуля VBA.
Небольшое примечание: это верно для модулей, модулей классов и т. Д., Которые пока не были открыты. Поэтому, если вы уже рассмотрели, например, код
Sheet1
перед тем как активировать опцию «Требовать объявление переменной»,Option Explicit
не будет добавлен!
Option Explicit
требует, чтобы каждая переменная была определена перед использованием, например, с помощью оператора Dim
. Без Option Explicit
, любое непризнанное слово будет приниматься компилятором VBA как новая переменная типа Variant
, вызывая чрезвычайно сложные ошибки, связанные с типографскими ошибками. Если Option Explicit
включена, любые непризнанные слова вызовут ошибку компиляции, указывая на строку нарушения.
Пример :
Если вы запустите следующий код:
Sub Test()
my_variable = 12
MsgBox "My Variable is : " & myvariable
End Sub
Появится следующее сообщение:
Вы сделали ошибку, написав myvariable
вместо my_variable
, затем в поле сообщения отображается пустая переменная. Если вы используете Option Explicit
, эта ошибка невозможна, потому что вы получите сообщение об ошибке компиляции, указывающее на проблему.
Теперь, если вы добавите правильное объявление:
Sub Test()
Dim my_variable As Integer
my_variable = 12
MsgBox "My Variable is : " & myvariable
End Sub
Вы получите сообщение об ошибке с указанием ошибки с myvariable
:
Примечание по Option Explicit и Array ( объявление динамического массива ):
Вы можете использовать оператор ReDim, чтобы объявить массив неявно в рамках процедуры.
Будьте осторожны, чтобы не пропустить имя массива при использовании оператора ReDim
Даже если оператор Option Explicit включен в модуль, будет создан новый массив
Dim arr() as Long
ReDim ar() 'creates new array "ar" - "ReDim ar()" acts like "Dim ar()"
Работа с массивами, а не с диапазонами
Офисный блог - лучшие методы кодирования производительности Excel VBA
Часто достигается наилучшая производительность, позволяя максимально избегать использования Range
. В этом примере мы читаем весь объект Range
в массив, каждый квадрат в массиве, а затем возвращаем массив обратно в Range
. Это позволяет получить доступ к Range
только дважды, тогда как цикл будет обращаться к нему 20 раз для чтения / записи.
Option Explicit
Sub WorkWithArrayExample()
Dim DataRange As Variant
Dim Irow As Long
Dim Icol As Integer
DataRange = ActiveSheet.Range("A1:A10").Value ' read all the values at once from the Excel grid, put into an array
For Irow = LBound(DataRange,1) To UBound(DataRange, 1) ' Get the number of rows.
For Icol = LBound(DataRange,2) To UBound(DataRange, 2) ' Get the number of columns.
DataRange(Irow, Icol) = DataRange(Irow, Icol) * DataRange(Irow, Icol) ' cell.value^2
Next Icol
Next Irow
ActiveSheet.Range("A1:A10").Value = DataRange ' writes all the results back to the range at once
End Sub
Дополнительные советы и информация с приуроченными примерами можно найти в статье Чарльза Уильямса «Эффективные VBA UDF» (часть 1) и других статьях в этой серии .
Используйте константы VB, если они доступны
If MsgBox("Click OK") = vbOK Then
могут быть использованы вместо
If MsgBox("Click OK") = 1 Then
чтобы улучшить удобочитаемость.
Используйте Object Browser, чтобы найти доступные константы VB. Просмотр → Обозреватель объектов или F2 из редактора VB.
Введите класс для поиска
Просмотреть участников
Использовать описательные имена переменных
Описательные имена и структура в коде помогут сделать комментарии ненужными
Dim ductWidth As Double
Dim ductHeight As Double
Dim ductArea As Double
ductArea = ductWidth * ductHeight
лучше, чем
Dim a, w, h
a = w * h
Это особенно полезно при копировании данных из одного места в другое, будь то ячейка, диапазон, рабочий лист или рабочая книга. Помогите себе, используя такие имена:
Dim myWB As Workbook
Dim srcWS As Worksheet
Dim destWS As Worksheet
Dim srcData As Range
Dim destData As Range
Set myWB = ActiveWorkbook
Set srcWS = myWB.Sheets("Sheet1")
Set destWS = myWB.Sheets("Sheet2")
Set srcData = srcWS.Range("A1:A10")
Set destData = destWS.Range("B11:B20")
destData = srcData
Если вы объявляете несколько переменных в одной строке, обязательно указывайте тип для каждой переменной:
Dim ductWidth As Double, ductHeight As Double, ductArea As Double
Следующие будут объявлять только последнюю переменную, а первая останется Variant
:
Dim ductWidth, ductHeight, ductArea As Double
Обработка ошибок
Хорошая обработка ошибок не позволяет конечным пользователям видеть ошибки времени выполнения VBA и помогает разработчику легко диагностировать и исправлять ошибки.
Существует три основных метода обработки ошибок в VBA, два из которых следует избегать для распределенных программ, если это специально не требуется в коде.
On Error GoTo 0 'Avoid using
или же
On Error Resume Next 'Avoid using
Предпочитают использовать:
On Error GoTo <line> 'Prefer using
По ошибке GoTo 0
Если в вашем коде не установлена ошибка, On Error GoTo 0
является обработчиком ошибок по умолчанию. В этом режиме любые ошибки времени выполнения запускают типичное сообщение об ошибке VBA, позволяющее либо закончить код, либо ввести режим debug
, идентифицируя источник. При написании кода этот метод является самым простым и полезным, но его всегда следует избегать для кода, который распространяется среди конечных пользователей, поскольку этот метод очень непригляден и затруднен для понимания конечными пользователями.
Вкл.
On Error Resume Next
VBA будет игнорировать любые ошибки, возникающие во время выполнения для всех строк, следующих за вызовом ошибки, до тех пор, пока обработчик ошибок не будет изменен. В очень конкретных случаях эта строка может быть полезна, но ее следует избегать за пределами этих случаев. Например, при запуске отдельной программы из макроса Excel вызов On Error Resume Next
может быть полезен, если вы не уверены, открыта ли программа или нет:
'In this example, we open an instance of Powerpoint using the On Error Resume Next call
Dim PPApp As PowerPoint.Application
Dim PPPres As PowerPoint.Presentation
Dim PPSlide As PowerPoint.Slide
'Open PPT if not running, otherwise select active instance
On Error Resume Next
Set PPApp = GetObject(, "PowerPoint.Application")
On Error GoTo ErrHandler
If PPApp Is Nothing Then
'Open PowerPoint
Set PPApp = CreateObject("PowerPoint.Application")
PPApp.Visible = True
End If
Если бы мы не использовали GetObject
вызов On Error Resume Next
и приложение Powerpoint еще не было открыто, метод GetObject
бы ошибку. Таким образом, для устранения двух экземпляров приложения необходимо было On Error Resume Next
.
Примечание. Также рекомендуется сразу же сбросить обработчик ошибок, как только вам больше не понадобится On Error Resume Next
вызова»
Вкл. Ошибка GoTo <строка>
Этот метод обработки ошибок рекомендуется для всего кода, который распространяется среди других пользователей. Это позволяет программисту точно контролировать, как VBA обрабатывает ошибку, отправив код в указанную строку. Тег можно заполнить любой строкой (включая числовые строки) и отправить код в соответствующую строку, за которой следует двоеточие. Несколько блоков обработки ошибок можно использовать, выполняя различные вызовы On Error GoTo <line>
. Нижеприведенная подпрограмма демонстрирует синтаксис вызова On Error GoTo <line>
.
Примечание. Важно, чтобы строка Exit Sub
была помещена над первым обработчиком ошибок и перед каждым последующим обработчиком ошибок, чтобы предотвратить естественный переход кода в блок без вызываемой ошибки. Таким образом, лучше всего использовать функцию и читаемость для размещения обработчиков ошибок в конце блока кода.
Sub YourMethodName()
On Error GoTo errorHandler
' Insert code here
On Error GoTo secondErrorHandler
Exit Sub 'The exit sub line is essential, as the code will otherwise
'continue running into the error handling block, likely causing an error
errorHandler:
MsgBox "Error " & Err.Number & ": " & Err.Description & " in " & _
VBE.ActiveCodePane.CodeModule, vbOKOnly, "Error"
Exit Sub
secondErrorHandler:
If Err.Number = 424 Then 'Object not found error (purely for illustration)
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
Else
MsgBox "Error " & Err.Number & ": " & Err.Desctription
Application.ScreenUpdating = True
Application.EnableEvents = True
Exit Sub
End If
Exit Sub
End Sub
Если вы выйдете из своего метода с кодом обработки ошибок, убедитесь, что вы очистили:
- Отменить все, что частично завершено
- Закрыть файлы
- Сбросить обновление экрана
- Сбросить режим расчета
- Сбросить события
- Сбросить указатель мыши
- Вызов метода выгрузки для экземпляров объектов, которые сохраняются после
End Sub
- Сброс строки состояния
Документируйте свою работу
Хорошей практикой является документирование вашей работы для последующего использования, особенно если вы кодируете динамическую рабочую нагрузку. Хорошие комментарии должны объяснять, почему код что-то делает, а не то, что делает код.
Function Bonus(EmployeeTitle as String) as Double
If EmployeeTitle = "Sales" Then
Bonus = 0 'Sales representatives receive commission instead of a bonus
Else
Bonus = .10
End If
End Function
Если ваш код настолько неясен, что он требует комментариев, чтобы объяснить, что он делает, подумайте о том, чтобы переписать его, чтобы быть более понятным, а не объяснять его с помощью комментариев. Например, вместо:
Sub CopySalesNumbers
Dim IncludeWeekends as Boolean
'Boolean values can be evaluated as an integer, -1 for True, 0 for False.
'This is used here to adjust the range from 5 to 7 rows if including weekends.
Range("A1:A" & 5 - (IncludeWeekends * 2)).Copy
Range("B1").PasteSpecial
End Sub
Уточнить код, который будет проще следовать, например:
Sub CopySalesNumbers
Dim IncludeWeekends as Boolean
Dim DaysinWeek as Integer
If IncludeWeekends Then
DaysinWeek = 7
Else
DaysinWeek = 5
End If
Range("A1:A" & DaysinWeek).Copy
Range("B1").PasteSpecial
End Sub
Отключение свойств во время выполнения макроса
Лучше всего на любом языке программирования избегать преждевременной оптимизации. Однако, если тестирование показывает, что ваш код работает слишком медленно, вы можете получить некоторую скорость, отключив некоторые свойства приложения во время его запуска. Добавьте этот код в стандартный модуль:
Public Sub SpeedUp( _
SpeedUpOn As Boolean, _
Optional xlCalc as XlCalculation = xlCalculationAutomatic _
)
With Application
If SpeedUpOn Then
.ScreenUpdating = False
.Calculation = xlCalculationManual
.EnableEvents = False
.DisplayStatusBar = False 'in case you are not showing any messages
ActiveSheet.DisplayPageBreaks = False 'note this is a sheet-level setting
Else
.ScreenUpdating = True
.Calculation = xlCalc
.EnableEvents = True
.DisplayStatusBar = True
ActiveSheet.DisplayPageBreaks = True
End If
End With
End Sub
Дополнительная информация о Office Blog - Excel VBA Performance Code Best Practices
И просто назовите его в начале и в конце макросов:
Public Sub SomeMacro
'store the initial "calculation" state
Dim xlCalc As XlCalculation
xlCalc = Application.Calculation
SpeedUp True
'code here ...
'by giving the second argument the initial "calculation" state is restored
'otherwise it is set to 'xlCalculationAutomatic'
SpeedUp False, xlCalc
End Sub
Хотя они могут в значительной степени рассматриваться как «усовершенствования» для обычных Public Sub
процедур Public Sub
, отключение обработки событий с помощью Application.EnableEvents = False
должно считаться обязательным для макросов частного события Worksheet_Change
и Workbook_SheetChange
которые изменяют значения на одном или нескольких листах. Невозможность отключить триггеры событий заставит макрос события рекурсивно запускаться поверх себя, когда значение изменится и может привести к «замороженной» книге. Не забудьте снова включить события, прежде чем покинуть макрос события, возможно, с помощью обработчика ошибок «безопасного выхода».
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Not Intersect(Target, Range("A:A")) Is Nothing Then
On Error GoTo bm_Safe_Exit
Application.EnableEvents = False
'code that may change a value on the worksheet goes here
End If
bm_Safe_Exit:
Application.EnableEvents = True
End Sub
Одно предостережение. Хотя отключение этих настроек улучшит время выполнения, они могут затруднить отладку приложения. Если код не работает надлежащим образом , закомментируйте SpeedUp True
вызов , пока вы не выяснить проблему.
Это особенно важно, если вы пишете ячейки на листе, а затем читаете в вычисленных результатах из функций листа, поскольку xlCalculationManual
позволяет xlCalculationManual
книгу. Чтобы обойти это без отключения SpeedUp
, вы можете включить Application.Calculate
для выполнения расчета в определенных точках.
ПРИМЕЧАНИЕ. Поскольку это свойства самого Application
, вам нужно убедиться, что они снова включены до того, как вы закончите макрос. Это делает особенно важным использование обработчиков ошибок и избежание множественных точек выхода (например, End
или Unload Me
).
С обработкой ошибок:
Public Sub SomeMacro()
'store the initial "calculation" state
Dim xlCalc As XlCalculation
xlCalc = Application.Calculation
On Error GoTo Handler
SpeedUp True
'code here ...
i = 1 / 0
CleanExit:
SpeedUp False, xlCalc
Exit Sub
Handler:
'handle error
Resume CleanExit
End Sub
Избегайте использования ActiveCell или ActiveSheet в Excel
Использование ActiveCell
или ActiveSheet
может быть источником ошибок , если (по любой причине) код выполняется в неправильном месте.
ActiveCell.Value = "Hello"
'will place "Hello" in the cell that is currently selected
Cells(1, 1).Value = "Hello"
'will always place "Hello" in A1 of the currently selected sheet
ActiveSheet.Cells(1, 1).Value = "Hello"
'will place "Hello" in A1 of the currently selected sheet
Sheets("MySheetName").Cells(1, 1).Value = "Hello"
'will always place "Hello" in A1 of the sheet named "MySheetName"
- Использование
Active*
может создавать проблемы в длинных макросах, если ваш пользователь скучает и нажимает на другой рабочий лист или открывает другую книгу. - Это может создать проблемы, если ваш код открывается или создает другую книгу.
- Это может создать проблемы, если ваш код использует
Sheets("MyOtherSheet").Select
и вы забыли, какой лист вы были, прежде чем начинать читать или писать на него.
Никогда не допускайте рабочий лист
Даже когда вся ваша работа направлена на один рабочий лист, все же очень хорошая практика явно указывать рабочий лист в вашем коде. Эта привычка значительно облегчает расширение вашего кода позже или поднять части (или все) Sub
или Function
которые будут повторно использоваться где-то еще. Многие разработчики устанавливают привычку (re) использовать одно и то же имя локальной переменной для рабочего листа в своем коде, что делает повторное использование этого кода еще более простым.
Например, следующий код неоднозначен, но работает! - пока разработчик не активирует или не переключается на другой рабочий лист:
Option Explicit
Sub ShowTheTime()
'--- displays the current time and date in cell A1 on the worksheet
Cells(1, 1).Value = Now() ' don't refer to Cells without a sheet reference!
End Sub
Если Sheet1
активен, ячейка A1 на Листе 1 будет заполнена текущей датой и временем. Но если пользователь по какой-либо причине меняет листы, тогда код обновит все текущие рабочие листы. Рабочий лист адресата неоднозначен.
Лучшая практика - всегда определять, какой лист, на который ссылается ваш код:
Option Explicit
Sub ShowTheTime()
'--- displays the current time and date in cell A1 on the worksheet
Dim myWB As Workbook
Set myWB = ThisWorkbook
Dim timestampSH As Worksheet
Set timestampSH = myWB.Sheets("Sheet1")
timestampSH.Cells(1, 1).Value = Now()
End Sub
Вышеприведенный код ясен при определении как рабочей книги, так и рабочего листа. Хотя это может показаться излишним, создание хорошей привычки в отношении целевых ссылок избавит вас от будущих проблем.
Избегайте использования SELECT или ACTIVATE
Очень редко вы когда-либо захотите использовать Select
или Activate
в своем коде, но некоторые методы Excel требуют, чтобы рабочий лист или рабочая книга были активированы до того, как они будут работать должным образом.
Если вы только начинаете изучать VBA, вам часто предлагается записать ваши действия с помощью макросъемщика, а затем взглянуть на код. Например, я записал действия, предпринятые для ввода значения в ячейке D3 на Sheet2, и макрокоманда выглядит следующим образом:
Option Explicit
Sub Macro1()
'
' Macro1 Macro
'
'
Sheets("Sheet2").Select
Range("D3").Select
ActiveCell.FormulaR1C1 = "3.1415" '(see **note below)
Range("D4").Select
End Sub
Помните, однако, макрорекордер создает строку кода для КАЖДОГО из ваших (пользовательских) действий. Это включает в себя щелчок на вкладке рабочего листа, чтобы выбрать Sheet2 ( Sheets("Sheet2").Select
), щелкнув по ячейке D3 перед вводом значения ( Range("D3").Select
) и с помощью клавиши Enter (которая эффективно « выбрав «ячейку ниже текущей выбранной ячейки: Range("D4").Select
).
Существует несколько проблем с использованием. .Select
здесь:
- Рабочий лист не всегда указывается. Это происходит, если вы не меняете рабочие листы во время записи и означает, что код даст разные результаты для разных активных рабочих листов.
-
.Select()
работает медленно. Даже если для параметраApplication.ScreenUpdating
установлено значениеFalse
, это необработанная операция, которая должна быть обработана. -
.Select()
неуправляем. ЕслиApplication.ScreenUpdating
остается равнымTrue
, Excel будет фактически выбирать ячейки, рабочий лист, форму ... независимо от того, с чем вы работаете. Это стрессово для глаз и действительно неприятно смотреть. -
.Select()
вызовет прослушиватели. Это уже немного продвинуто, но если не работать, будут запускаться такие функции, какWorksheet_SelectionChange()
.
Когда вы кодируете в VBA, все действия «набрав» (т. Select
Команды Select
) больше не нужны. Ваш код может быть сведен к одному оператору, чтобы поместить значение в ячейку:
'--- GOOD
ActiveWorkbook.Sheets("Sheet2").Range("D3").Value = 3.1415
'--- BETTER
Dim myWB As Workbook
Dim myWS As Worksheet
Dim myCell As Range
Set myWB = ThisWorkbook '*** see NOTE2
Set myWS = myWB.Sheets("Sheet2")
Set myCell = myWS.Range("D3")
myCell.Value = 3.1415
(Пример BETTER выше показывает использование промежуточных переменных для разделения разных частей ссылки на ячейку. Пример GOOD всегда будет работать очень хорошо, но может быть очень громоздким в гораздо более длинных модулях кода и более сложным для отладки, если одна из ссылок неверна. )
** ПРИМЕЧАНИЕ. Макросъемщик делает много предположений о типе данных, которые вы вводите, в этом случае вводите строковое значение в качестве формулы для создания значения. Ваш код не должен делать этого и может просто назначить числовое значение непосредственно ячейке, как показано выше.
** Примечание 2: рекомендуемая практика , чтобы установить локальную переменную рабочую книгу ThisWorkbook
вместо ActiveWorkbook
(если явно не нужно). Причина заключается в том, что ваш макрос обычно должен / использовать ресурсы в любой книге, из которой возникает код VBA, и НЕ будет выглядеть за пределами этой книги - опять же, если вы явно не назовете свой код работать с другой книгой. Когда вы открываете несколько книг в Excel, ActiveWorkbook
- это та, которая может отличаться от рабочей книги, просматриваемой в редакторе VBA . Итак, вы думаете, что работаете в одной книге, когда вы действительно ссылаетесь на другую. ThisWorkbook
относится к книге, содержащей исполняемый код.
Всегда определяйте и устанавливайте ссылки на все книги и таблицы
При работе с несколькими открытыми рабочими книгами, каждая из которых может иметь несколько листов, наиболее безопасно определить и установить ссылку на все книги и таблицы.
Не полагайтесь на ActiveWorkbook
или ActiveSheet
поскольку они могут быть изменены пользователем.
В следующем примере кода показано , как скопировать диапазон от листа «Raw_Data» в книге «Data.xlsx» на листе «Refined_Data» в книге «Results.xlsx».
Эта процедура также демонстрирует, как копировать и вставлять, не используя метод Select
.
Option Explicit
Sub CopyRanges_BetweenShts()
Dim wbSrc As Workbook
Dim wbDest As Workbook
Dim shtCopy As Worksheet
Dim shtPaste As Worksheet
' set reference to all workbooks by name, don't rely on ActiveWorkbook
Set wbSrc = Workbooks("Data.xlsx")
Set wbDest = Workbooks("Results.xlsx")
' set reference to all sheets by name, don't rely on ActiveSheet
Set shtCopy = wbSrc.Sheet1 '// "Raw_Data" sheet
Set shtPaste = wbDest.Sheet2 '// "Refined_Data") sheet
' copy range from "Data" workbook to "Results" workbook without using Select
shtCopy.Range("A1:C10").Copy _
Destination:=shtPaste.Range("A1")
End Sub
Объект WorksheetFunction выполняется быстрее, чем эквивалент UDF
VBA компилируется во время выполнения, что оказывает огромное негативное влияние на его производительность, все встроенное будет быстрее, попробуйте использовать их.
В качестве примера я сравниваю функции SUM и COUNTIF, но вы можете использовать, если для чего-нибудь, что вы можете решить с помощью WorkSheetFunctions.
Первой попыткой для них было бы перебрать диапазон и обработать его ячейкой по ячейке (используя диапазон):
Sub UseRange()
Dim rng as Range
Dim Total As Double
Dim CountLessThan01 As Long
Total = 0
CountLessThan01 = 0
For Each rng in Sheets(1).Range("A1:A100")
Total = Total + rng.Value2
If rng.Value < 0.1 Then
CountLessThan01 = CountLessThan01 + 1
End If
Next rng
Debug.Print Total & ", " & CountLessThan01
End Sub
Одним из улучшений может быть сохранение значений диапазона в массиве и процесс, который:
Sub UseArray()
Dim DataToSummarize As Variant
Dim i As Long
Dim Total As Double
Dim CountLessThan01 As Long
DataToSummarize = Sheets(1).Range("A1:A100").Value2 'faster than .Value
Total = 0
CountLessThan01 = 0
For i = 1 To 100
Total = Total + DataToSummarize(i, 1)
If DataToSummarize(i, 1) < 0.1 Then
CountLessThan01 = CountLessThan01 + 1
End If
Next i
Debug.Print Total & ", " & CountLessThan01
End Sub
Но вместо написания любого цикла вы можете использовать Application.Worksheetfunction
что очень удобно для выполнения простых формул:
Sub UseWorksheetFunction()
Dim Total As Double
Dim CountLessThan01 As Long
With Application.WorksheetFunction
Total = .Sum(Sheets(1).Range("A1:A100"))
CountLessThan01 = .CountIf(Sheets(1).Range("A1:A100"), "<0.1")
End With
Debug.Print Total & ", " & CountLessThan01
End Sub
Или, для более сложных вычислений вы можете даже использовать Application.Evaluate
:
Sub UseEvaluate()
Dim Total As Double
Dim CountLessThan01 As Long
With Application
Total = .Evaluate("SUM(" & Sheet1.Range("A1:A100").Address( _
external:=True) & ")")
CountLessThan01 = .Evaluate("COUNTIF('Sheet1'!A1:A100,""<0.1"")")
End With
Debug.Print Total & ", " & CountLessThan01
End Sub
И, наконец, работая над Subs 25 000 раз каждый, вот среднее (5 тестов) время в миллисекундах (конечно, это будет отличаться на каждом ПК, но по сравнению друг с другом они будут вести себя аналогичным образом):
- UseWorksheetFunction: 2156 мс
- UseArray: 2219 мс (+ 3%)
- UseEvaluate: 4693 мс (+ 118%)
- UseRange: 6530 мс (+ 203%)
Избегайте повторного назначения имен свойств или методов в качестве переменных
Обычно не считается «лучшей практикой» повторно назначать зарезервированные имена свойств или методов как имя (имена) ваших собственных процедур и переменных.
Плохая форма. В то время как следующий (строго говоря) законный, рабочий код повторное назначение метода Find, а также свойства Row , Column и Address могут вызвать проблемы / конфликты с неоднозначностью имени и просто путают в целом.
Option Explicit
Sub find()
Dim row As Long, column As Long
Dim find As String, address As Range
find = "something"
With ThisWorkbook.Worksheets("Sheet1").Cells
Set address = .SpecialCells(xlCellTypeLastCell)
row = .find(what:=find, after:=address).row '< note .row not capitalized
column = .find(what:=find, after:=address).column '< note .column not capitalized
Debug.Print "The first 'something' is in " & .Cells(row, column).address(0, 0)
End With
End Sub
Хорошая форма. Все зарезервированные слова, переименованные в близкие, но уникальные аппроксимации оригиналов, избегали любых возможных конфликтов имен.
Option Explicit
Sub myFind()
Dim rw As Long, col As Long
Dim wht As String, lastCell As Range
wht = "something"
With ThisWorkbook.Worksheets("Sheet1").Cells
Set lastCell = .SpecialCells(xlCellTypeLastCell)
rw = .Find(What:=wht, After:=lastCell).Row '◄ note .Find and .Row
col = .Find(What:=wht, After:=lastCell).Column '◄ .Find and .Column
Debug.Print "The first 'something' is in " & .Cells(rw, col).Address(0, 0)
End With
End Sub
Хотя может наступить время, когда вы хотите намеренно переписать стандартный метод или свойство в соответствии со своими собственными спецификациями, эти ситуации немногочисленны и далеки друг от друга. По большей части избегайте повторного использования зарезервированных имен для ваших собственных конструкций.