. VBA】Setとは?オブジェクト変数の使い方とNothingの意味を解説 ~地道に学ぶExcelVBA~
VBA】Setとは?オブジェクト変数の使い方とNothingの意味を解説 ~地道に学ぶExcelVBA~
VBA】Setとは?オブジェクト変数の使い方とNothingの意味を解説 ~地道に学ぶExcelVBA~

Setとは? オブジェクト変数の使い方とNothingの意味を解説

Workbook型やWorksheet型の変数の最後に半角ドットをつけると、メソッドやプロパティの候補一覧が表示されます。 メソッドとプロパティは(語弊はありますが)簡単に言うと、メソッドはオブジェクト変数でのみ使用できる専用の関数、プロパティはオブジェクト変数でのみ使用できる専用の変数と覚えてください。 ただし、Object型で宣言した後は候補一覧が表示されないため、注意が必要です。 Setを使用するのは、変数とオブジェクトを紐づける時のみで、メソッドやプロパティを使用する時はSetを付ける必要はありません。 文字通り、Set=設定する、ということですね。

Functionプロシージャでオブジェクトを返す場合

Functionプロシージャでオブジェクトを返す場合、 Function名で返す時と、呼び出し元で受け取る際の2か所でSetを使用する 必要があります。

Function SampleSet1() Set SampleSet1 = ThisWorkbook.Worksheets(1) End Function Sub Main1() Dim ws As Worksheet Set ws = SampleSet1 End Sub 【例外】引数でオブジェクト変数に参照先を格納する場合

Functionプロシージャの引数をオブジェクトを渡すことが出来ます。 なお、 オブジェクト(オブジェクト変数)を引数にする場合、"Set"を付ける必要がありません。

Function SampleSet2(wb as Workbook) '← ここは Set 不要 '何らかの処理 End Function Sub Main() ’マクロを実行しているブックオブジェクトを送る SampleSet2 ThisWorkbook End Sub オブジェクト変数の参照を解除する Set 変数 = Nothing

Set 変数 = Nothing を使うと、オブジェクト変数の初期化(メモリの解放)を行うことができます。ただし、VBAでは自動的に初期化がありますので、通常は不要となります。詳細は、後述します。

Setの使用例 ブックをオブジェクト変数に代入する Sub sample1_1() 'Workbook型の変数wbを作成する Dim wb As Workbook '変数wbに実行しているブックオブジェクトを参照させる Set wb = ThisWorkbook '実行しているブックを閉じる wb.Close '←ThisWorkbook.Close と同じ End Sub シートをオブジェクト変数に代入する Sub SetSample1_2() Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets(1) '実行しているシート名を表示する MsgBox ws.Name '←MsgBox ThisWorkbook.Worksheets(1).Name と同じ End Sub Setを使うメリットは?

    見やすさ(可読性)が大きく向上する Set を使用するとプログラムが短くなり、読みやすくなります。 Setを使用しないパターンと使用するパターンを比較してみます。 まずは、Set を使用しないパターンです。

Sub SetSample2_1() ThisWorkbook.Worksheets("Sheet1").Range("A1") = _ ThisWorkbook.Worksheets("Sheet2").Range("B2") ThisWorkbook.Worksheets("Sheet1").Range("C1") = _ ThisWorkbook.Worksheets("Sheet2").Range("D2") ThisWorkbook.Worksheets("Sheet2").Range("D1") = _ ThisWorkbook.Worksheets("Sheet1").Range("D3") ThisWorkbook.Worksheets("Sheet2").Range("D3") = _ ThisWorkbook.Worksheets("Sheet1").Range("D6") End Sub 次に、Set を使用するパターンです。 Sub SetSample2_2() Dim wsMain As Worksheet Dim wsConf As Worksheet Set wsMain = ThisWorkbook.Worksheets("Sheet1") Set wsConf = ThisWorkbook.Worksheets("Sheet2") wsMain.Range("A1") = wsConf.Range("B2") wsMain.Range("C1") = wsConf.Range("D2") wsConf.Range("D1") = wsMain.Range("D3") wsConf.Range("D3") = wsMain.Range("D6") Set wsMain = Nothing Set wsConf = Nothing End Sub Function GetRangeObj(ws As Worksheet, ByVal 範囲 As String) As Range Set GetRangeObj = ws.Range(範囲) End Function Sub SetSample2_3() Dim rng As Range Set rng = GetRangeObj(ThisWorkbook.Worksheets(1), "C2:C5") rng.Interior.Color = RGB(0, 255, 0) ' 背景色を緑にする Set rng = Nothing End Sub 引数でオブジェクト変数を渡せば、戻り値にしなくても大丈夫だったりします。 ただし、可読性が著しく下がるため、お勧めしません。 ’長いプログラムだと、どこでrngの参照を設定したか分からない Sub SetRangeObj(ws As Worksheet, rng As Range, ByVal 範囲 As String) Set rng = ws.Range(範囲) End Sub Sub SetSample2_4() Dim rng As Range SetRangeObj ThisWorkbook.Worksheets(1), rng, "D2:D5" rng.Interior.Color = RGB(0, 255, 255) ' 背景色を水色にする Set rng = Nothing End Sub Setのありがちなミス 【実行時エラー 91】Setのつけ忘れ

これまで述べてきた通り、オブジェクトの参照を変数に格納する場合、変数の前に"Set"を付ける必要があります。 この場合「実行時エラー 91」が発生します。

'実行時エラー 91になる(Sheet1のセルA1に"a"を格納したかった) Sub SetSample3_1() Dim ws As Worksheet '先頭に"Set" を忘れているため、エラーが発生する _ ※「Set ws = Worksheets("Sheet1")」が正しい ws = Worksheets("Sheet1") ws.Cells(1, 1) = "a" End Sub 【実行時エラー 438】存在しないプロパティやメソッドを参照

存在しないプロパティやメソッドを参照すると「実行時エラー 438」が発生します。 Object型へ想定していたオブジェクトと異なるオブジェクトを代入したケースがあります。他に、プロパティ名やメソッド名をタイプミスしたケースがあります。

Object型へ想定していたオブジェクトと異なるオブジェクトを代入したケース '実行時エラー 438になる(ブックを閉じたかった) Sub SetSample3_2_1() Dim wb As Object '"Worksheets" は不要(ミス) Set wb = ThisWorkbook.Worksheets 'WorksheetsオブジェクトにCloseメソッドはない wb.Close ' ←ここでエラーが発生する End Sub プロパティ名やメソッド名をタイプミスしたケース '実行時エラー 438になる(シート名を変えたかった) Sub SetSample3_2_2() Dim ws As Object Set ws = Worksheets(1) 'ws.Name が正しい(Namee になっている) ws.Namee = "シート1" ' ←ここでエラーが発生する End Sub

Object型でなく、Worksheet型で変数を作成すると「コンパイルエラー:メソッドまたはデータメンバーが見つかりません。」とエラーメッセージが表示されます。 可能であれば、Object型を使用せず、Worksheet型等を指定 するようにしましょう。

【論理エラー】2つのオブジェクト変数が干渉し合っている

2つのオブジェクト変数を作成し参照先が同じオブジェクト コンパイルエラーや実行時エラー等にならない論理エラー(プログラムは実行できるが想定と異なること)です。 2つの変数が同じオブジェクトを参照している場合、片方の変数を通じてオブジェクトを変更すると、もう片方の変数から参照したときに変更内容が反映されています。 あくまで、オブジェクト変数は1つのオブジェクトを参照しているだけで、実体は1つだからです。

Sub SetSample3_3_1() Dim wb1 As Workbook Dim wb2 As Workbook Set wb1 = ThisWorkbook Set wb2 = wb1 '↓wb1のSheet1のセルA1も"Hello"となる wb2.Worksheets("Sheet1").Range("A1") = "Hello!" End Sub

SetSample3_3_1 と SetSample3_3_2は同じ結果になります。

Sub SetSample3_3_2() Dim wb1 As Workbook Dim wb2 As Workbook Set wb1 = ThisWorkbook Set wb2 = wb1 '↓【wb2】のSheet1のセルA1も"Hello"となる wb1.Worksheets("Sheet1").Range("A1") = "Hello!" End Sub Set 変数 = Nothing は必要?

普通にVBAを使用する分には、不要となります。 なぜなら、VBAには、参照カウント方式という、オブジェクト変数の参照が完全になくなると、自動的にメモリが解放される仕組みがあります。 ただし、大きいプロシージャや大量のデータ、大規模な配列を使用する場合、メモリを解放する必要があります。 また、循環参照など特殊なケースではメモリが残ってしまうこともあるため、Set = Nothingを使って明示的に解放することが推奨される場面があります。

'Nothingの使用例 Sub SetSample4_2() Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets(1) MsgBox ws.Name '←MsgBox ThisWorkbook.Worksheets(1).Name と同じ 'オブジェクト変数を初期化(解放)する Set ws = Nothing End Sub

確認テスト

  1. 次の条件を満たすプログラムを作成しなさい。
  2. マクロを実行しているブックの左から1番目のシートオブジェクトを取得する
  3. シートオブジェクトより、シート名を「hoge」と変更する

Sub SetAnswer1() Dim ws As Worksheet Set ws = ThisWorkbook.Worksheets(1) ws.Name = "hoge" Set ws = Nothing End Sub ' シートオブジェクトを返すだけのプロシージャ Function GetSheetObj(Byval sName As String) As Worksheet Set GetSheetObj = ThisWorkbook.Worksheets(sName) End Function Sub SetAnswer2() Dim ws As Worksheet Set ws = GetSheetObj(ThisWorkbook.Worksheets(2).Name) MsgBox ws.Name Set ws = Nothing End Sub

関連リンク

  • 次ページ:VBAでエクセルファイルやCSVファイルを開く
  • 前ページ:指定のブックのセルのデータを取得・格納する
  • 【実行時エラー91】オブジェクト変数または With ブロック変数が設定されていません。

Copyright © 2018 ExcelVBA.Work All Rights Reserved.

📎📎📎📎📎📎📎📎📎📎