excel-vba
VBAベストプラクティス
サーチ…
備考
私たちは皆それを知っていますが、これらの慣行はVBAでプログラムを始める人にとってははるかに明らかではありません。
常に "Option Explicit"を使用してください。
VBAエディタウィンドウで、[ツール]メニューから[オプション]を選択します。
次に、[エディタ]タブで、[変数宣言が必要]チェックボックスがオンになっていることを確認します。
このオプションを選択すると、 Option Explicit
がすべてのVBAモジュールの先頭に自動的に配置されます。
小さなメモ:これはこれまでに開かれていないモジュール、クラスモジュールなどに当てはまります。たとえば、オプション "Require Variable Declaration"を有効にする前に
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
のエラーを正確に示すエラーメッセージが表示されmyvariable
。
Option Explicit and Arrays ( 動的配列の宣言 ) に関する注意 :
ReDimステートメントを使用して、プロシージャー内で暗黙的に配列を宣言することができます。
ReDimステートメントを使用するとき、配列の名前のスペルを間違えないように注意してください
Option Explicitステートメントがモジュールに含まれていても、新しい配列が作成されます
Dim arr() as Long
ReDim ar() 'creates new array "ar" - "ReDim ar()" acts like "Dim ar()"
範囲ではなく配列で作業する
Officeブログ - Excel VBAパフォーマンスコーディングのベストプラクティス
可能な限りRange
の使用を避けることによって、最高のパフォーマンスが得られることがよくあります。この例では、 Range
オブジェクト全体を配列に読み込み、配列内の各番号を四角にしてから、配列をRange
戻します。 Range
は、 Range
2回しかアクセスしませんが、ループは、読み取り/書き込みのために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
読みやすさを向上させるためです。
オブジェクトブラウザを使用して、利用可能なVB定数を検索します。 ビュー→オブジェクトブラウザまたはVBエディタからのF2
検索するクラスを入力
利用可能なメンバーを表示
記述的な変数命名を使用する
コード内の記述的な名前と構造は、コメントを不要にするのに役立ちます
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
1つの行に複数の変数を宣言する場合は、以下のように各変数の型を指定してください。
Dim ductWidth As Double, ductHeight As Double, ductArea As Double
以下は最後の変数のみを宣言し、最初の変数はVariant
ままです。
Dim ductWidth, ductHeight, ductArea As Double
エラー処理
良好なエラー処理により、エンドユーザーはVBAランタイムエラーを見ることができなくなり、開発者はエラーを簡単に診断して修正することができます。
VBAでは3つの主なエラー処理方法がありますが、コードで特に必要とされている場合を除き、2つは分散プログラムでは避けるべきです。
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
On Error Resume Next
呼び出しを使用せず、Powerpointアプリケーションがまだ開いていない場合、 GetObject
メソッドはエラーをスローします。したがって、 On Error Resume Next
は、アプリケーションの2つのインスタンスを作成しないようにするために必要でした。
注:また、エラーハンドラをすぐにリセットするには、 On Error Resume Next
コールが不要になったらすぐにリセットすることをお勧めします
エラー時にGoTo <line>
このエラー処理方法は、他のユーザーに配布されているすべてのコードに対してお勧めします。これにより、プログラマは、指定された行にコードを送信することにより、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ブログの詳細- Excel VBAパフォーマンスコーディングのベストプラクティス
そして、それをマクロの始めと終わりに呼び出します:
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
プロシージャの「拡張」と見なすことができますが、 Application.EnableEvents = False
イベント処理を無効にすることは、 Worksheet_Change
値を変更する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
までSpeedUp True
呼び出しをコメントアウトしてください。
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
ExcelでActiveCellまたはActiveSheetを使用しないようにする
何らかの理由でコードが間違った場所で実行された場合、 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
使用している場合、問題が発生する可能性がありますSheets("MyOtherSheet").Select
、読み書きを開始する前にどのシートにいるかを忘れてしまいました。
ワークシートを決して使わない
すべての作業が単一のワークシートに指示されている場合でも、コード内にワークシートを明示的に指定することは、非常に良い方法です。この習慣により、後でコードを拡張したり、 Sub
やFunction
一部(またはすべて)を他の場所で再利用するほうがずっと簡単になります。多くの開発者は、コード内のワークシートに同じローカル変数名を使用するという習慣を確立し、そのコードの再利用をさらに簡単にします。
例として、次のコードはあいまいですが、動作します! - 開発者が別のワークシートをアクティブ化または変更しない限り、
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
がアクティブな場合は、 Sheet1
A1セルに現在の日付と時刻が入力されます。しかし、ユーザーが何らかの理由でワークシートを変更した場合、コードはワークシートが現在アクティブであるものを更新します。宛先ワークシートはあいまいです。
ベストプラクティスは、コードが参照するワークシートを常に識別することです。
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の習得を始めたばかりの方は、マクロレコーダーを使ってアクションを記録し、コードを見てみることをおすすめします。たとえば、Sheet2のセルD3に値を入力するために実行されたアクションを記録し、マクロコードは次のようになります。
Option Explicit
Sub Macro1()
'
' Macro1 Macro
'
'
Sheets("Sheet2").Select
Range("D3").Select
ActiveCell.FormulaR1C1 = "3.1415" '(see **note below)
Range("D4").Select
End Sub
しかし、マクロレコーダーはあなたの(ユーザー)アクションごとに1行のコードを作成することを覚えておいてください。これは、ワークシート・タブをクリックしてシート2( Sheets("Sheet2").Select
)をSheets("Sheet2").Select
、値D3を入力する前にセルD3をクリックしてRange("D3").Select
し、現在選択されているセルの下のセルを選択する: Range("D4").Select
)。
.Select
使用には複数の問題があります:
- ワークシートは常に指定されているわけではありません。これは、記録中にワークシートを切り替える必要がない場合に発生し、さまざまなアクティブなワークシートに対して異なる結果をもたらすことを意味します。
-
.Select()
は遅いです。Application.ScreenUpdating
がFalse
に設定されていても、これは処理される不必要な操作です。 -
.Select()
は.Select()
です。Application.ScreenUpdating
がTrue
ままになっていると、Excelは実際にはセル、ワークシート、フォームなどを選択します。これは目にストレスがあり、見るのが本当に不愉快です。 -
.Select()
はリスナーをトリガーします。これはもう少し進んでいますが、回避しなければ、Worksheet_SelectionChange()
ような関数がトリガされます。
VBAでコーディングしているときは、「タイプする」アクション(つまりSelect
ステートメント)はすべて必要なくなりました。コードを1つのステートメントに減らして、値をセルに入れることができます。
'--- 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
(上のより良い例では中間変数を使ってセル参照の異なる部分を区切っていますが、GOODの例は常にうまく動作しますが、ずっと長いコードモジュールでは扱いにくく、参照の1つが誤っているとデバッグが難しくなります。 )
**注:マクロレコーダーは、入力するデータの種類について多くの仮定を行います。この場合、値を作成する式として文字列値を入力します。あなたのコードはこれを行う必要はなく、上記のように単にセルに直接数値を割り当てることができます。
** NOTE2:推奨される方法は、 ActiveWorkbook
代わりにローカルワークブック変数をThisWorkbook
に設定することです(明示的に必要な場合を除きます)。なぜなら、マクロは、VBAコードがどのようなワークブックであっても、そのワークブックの外側には見えないようなリソースを必要とします。 Excelで複数のワークブックを開いている場合、 ActiveWorkbook
は、 VBAエディタで表示されているワークブックとは異なるフォーカスを持つワークブックです。つまり、実際に別のワークブックを参照しているときに1つのワークブックで実行していると思います。 ThisWorkbook
は、実行されているコードを含むブックを参照します。
すべてのワークブックとシートへの参照を常に定義および設定する
複数の開いているワークブックで作業する場合は、それぞれに複数のシートがある場合は、すべてのワークブックとシートを参照して定義するのが最も安全です。
ActiveWorkbook
またはActiveSheet
は、ユーザーによって変更される可能性があるため 、 依存しないでください 。
次のコード例は、「Data.xlsx」ワークブックの「RAW_DATA」シートから「Results.xlsx」ワークブックの「Refined_Data」シートの範囲をコピーする方法を示します。
また、 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で解決できるものなら、ifを使うことができます。
それらの最初の試みは、範囲をループし、セルごとにセルを処理することです(範囲を使用して)。
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
1つの改善点は、範囲値を配列に格納し、次のように処理することです。
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
使用することもでき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
そして、最終的に、各25,000回のSubsを超えて走っているここでは、平均(5回のテスト)時間がミリ秒単位で表示されます(もちろん、各PCで異なるでしょうが、お互いに比べて同様に動作します)。
- UseWorksheetFunction:2156ミリ秒
- UseArray:2219 ms(+ 3%)
- UseEvaluate:4693 ms(+ 118%)
- UseRange:6530 ms(+ 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
標準のメソッドやプロパティを独自の仕様に意図的に書き換えたいときが来るかもしれませんが、そのような状況はほとんどありません。ほとんどの場合、独自の構造の予約された名前を再利用しないでください。