※本ブログのページには広告主との提携による広告や宣伝、プロモーションが含まれます。当ブログを経由しての商品の購入や、サービス申し込みが発生すると、それらの提携企業からの成果報酬を受けとる場合があります。

エクセルVBA|Withステートメントの使い方と注意点

 エクセルVBAで同じオブジェクトに対して複数の操作を行うとき、どのようにコードを書いていますか?
オブジェクト名を何度も繰り返し書いていませんか?

 エクセルVBAでは、同じオブジェクトに対して処理を書くときは、Withステートメントを使えます。
 Withステートメントは、指定オブジェクトに対する処理をまとめて書くことができるため、マクロのコードをスッキリすることさせる効果があります。

 Withステートメントをつかうことで、マクロの可読性の向上につながります。プログラミングでは、可読性の向上(読みやすくなること)は、不具合の原因を見つけやすくなることや、機能のアップデートなどでの作業ミスを防止する効果があります。

 また、特定のオブジェクトで複数のプロパティを設定するときなどの場面では、オブジェクトを繰り返し参照する必要がなくなることから、何度もオブジェクトを参照するケースと比較して処理が早くなるといったメリットもあります。

 この記事では、エクセルVBAにおけるWithステートメントの基本的な使い方と使用時の注意事項について解説します。

WithステートメントはVBAのコードをスリム化できるものだよ。

独学だと中々スキルが身についた実感が湧かない。学習環境を見直してみませんか?

エクセルで繰り返しや転記作業で苦しい思いをした経験はありませんか?
今まで苦労してきたその作業を簡単なプログラムをおぼえるだけで解決できる可能性があります。
なるべくお金や時間をかけずにエクセルマクロVBAを習得したい人にはこちらの「1日速習講座」がおすすめです。

VBAにおけるWithステートメントの概要とメリット

 Withステートメントとは、同じオブジェクトに対して複数のプロパティやメソッドを指定するときに使う構文です。Withステートメントを使うと、オブジェクト名を一度だけ書いて、その後の操作をピリオド(.)でつなげることができます。Withステートメントの書き方は以下です。

With オブジェクト

  .プロパティやメソッド
  .プロパティやメソッド

End With

 Withステートメントの最大メリットは、VBAのコードがスリムになり見やすくなることです。
オブジェクト名を繰り返し書く必要がなくなるので、全体のコードの量が減り、読みやすく、理解しやすくなります。また、オブジェクト名を書き間違える可能性が減ることもメリットと言えます。

 さらにWithステートメントを使うと、オブジェクトの参照が高速になるというメリットもあります。これは、Withステートメント内ではオブジェクトの参照が一時的に蓄積されることで素早く取り出せるためです。

 Withステートメントの使うイメージをあくまで個人的な感覚でお伝えするとすれば、主語や目的語をまとめるという表現になるかと思います。この言葉を念頭に置きながら記事を読み進めて頂いたあなたの理解につながればうれしいです。

アーニャ・フォージャーの性別は 女のこ です。

アーニャ・フォージャーの学校は イーデン校 です。

アーニャ・フォージャーの能力は 他人の心をよむこと です。

ここでは「アーニャ・フォージャー」が主語となっていますが、3つの文章すべてにアーニャ・フォージャーが書かれていると冗長な表現となっています。

こちらの文章をWithステートメントをつかってスリムにしてみます。

アーニャ・フォージャー

 性別は 女のこ です。

 学校は イーデン校 です。

 能力は 他人の心をよむこと です。

アーニャ・フォージャー」の部分をWithステートメントでまとめたことによって、それ以降の性別や学校、能力を説明する行では同じ言葉である「アーニャ・フォージャー」を省略することができます。

って、ただそれだけ?だと思われるかもしれませんが、ここで説明した例では「アーニャ・フォージャー」といった言葉が短いため、文字数もそれほど変わりませんが、これが「アーニャ・フォージャーの父親の同僚の赤メガネの男性」のように長いものであった場合「アーニャ・フォージャーの父親の同僚の赤メガネの男性」の文字列を繰り返し書かないだけでもプログラムのコードをすっきりさせることができます。

Withで囲った部分の主語をまとめるイメージだね。

それでは、次からはWithステートメントの書きかたを説明していきます。

VBAのWithステートメントの基本的な書き方

それでは、Withステートメントの基本的な書き方についてみていきましょう。

構文

With object [ statements ] End With

Withステートメントをつかうためには、With オブジェクト(Object)からEnd Withまでの間に指定したオブジェクトに対するプロパティやメソッドを書きます。さきほど紹介した文章をVBAのコードのように書いてみます。

With アーニャ・フォージャー

 性別は 女のこ です。
 学校は イーデン校 です。
 能力は 他人の心をよむこと です。

End With

 Withステートメントは、繰り返しのオブジェクト参照をスリム化するために使います。

そのため、指定項目では オブジェクト(Object)の指定は必須となります。オブジェクト(Object)には、ブック(ファイル)、セル、ワークシート、グラフ、フォームなどのほかに、クラスなどの作成したオブジェクトの参照も可能です。

 With ステートメントを使用することで、特定のオブジェクトやユーザー定義型に対してオブジェクト名の指定を繰り返し書く必要がなくなり、Withステートメントでまとめて実行できます。

具体的には、1 つのオブジェクトにあるそれぞれのプロパティを変更したいときなどに有効です。

Withステートメントの指定項目について
指定項目 必須/省略可 説明
object 必須 参照したいオブジェクトやユーザー定義型の名前を指定します。
statements 省略可 object に対して実行する1つ以上のステートメントを指定します。

With object ~ End Withが間に書いたオブジェクトがまとめられるよ。

独学でプログラミングをはじめてみたけど、このままの学習方法に不安を感じているのなら、
オンラインスクールで現役エンジニアのサポートがあるテックアカデミーがおすすめ。
スキマ時間に学べて仕事も保証。必ず副業、始められます。まずは無料でプログラミング体験

Withステートメントを使ったサンプルマクロ

 Withステートメントの使ったサンプルマクロを紹介します。

 ここでは、エクセルのシート1のA1セルからF6セルまでの編集をするマクロにおいて、ワークシートオブジェクトのシート1をWithステートメントで参照した場合と、Withステートメントなしで、繰り返しワークシートオブジェクトを参照するVBAコードで比較しています。(どちらも全く同じ処理をするマクロです)

Withステートメントありのサンプルコード
  
Option Explicit

Sub withステートメント使用例1()
    
    'Withステートメントでこのブック(ファイル)のワークシート1のオブジェクトを参照する
    With ThisWorkbook.Worksheets(1)
    
        'セルA1に"With"を入力する
        .Range("A1").Value = "With"
        
        'セルB2の背景色を3(赤色)にする
        .Range("B2").Interior.ColorIndex = 3
        
        'セルC3にC3セルのアドレスを入力する
        .Range("C3").Value = .Range("C3").Address
        
        'セルD4にセル(オブジェクト)数を入力する
        .Range("D4") = .Range("D4").Count
        
        'セルE5にE5セルの行数を入力する
        .Range("E5").Value = .Range("E5").Row
        
        'セルF6にF6セルの列数を入力する
        .Range("F6").Value = .Range("F6").Column
    
    End With

End Sub

 ポイントは、Withステートメントをつかってシートオブジェクトのシート1を参照している点です。
これによって、シート内のセルをするときにシートオブジェクトを何度も書く必要がなくなりました。Withステートメントでオブジェクトを参照している行は、ピリオド(.)から書きはじめます。

Withで参照している部分は、ピリオドをつけることを忘れないようにね。

Withステートメントなしのサンプルコード
  
Option Explicit

Sub withステートメント使用しない()

        'セルA1に"With"を入力する
        ThisWorkbook.Worksheets(1).Range("A1").Value = "With"
        
        'セルB2の背景色を3(赤色)にする
        ThisWorkbook.Worksheets(1).Range("B2").Interior.ColorIndex = 3
        
        'セルC3にC3セルのアドレスを入力する
        ThisWorkbook.Worksheets(1).Range("C3").Value = ThisWorkbook.Worksheets(1).Range("C3").Address
        
        'セルD4にセル(オブジェクト)数を入力する
        ThisWorkbook.Worksheets(1).Range("D4") = ThisWorkbook.Worksheets(1).Range("D4").Count
        
        'セルE5にE5セルの行数を入力する
        ThisWorkbook.Worksheets(1).Range("E5").Value = ThisWorkbook.Worksheets(1).Range("E5").Row
        
        'セルF6にF6セルの列数を入力する
        ThisWorkbook.Worksheets(1).Range("F6").Value = ThisWorkbook.Worksheets(1).Range("F6").Column

End Sub

 Withステートメントをつかったサンプルコードと比較すると、オブジェクトを参照するためのコードの分だけ長くなっています。

 このサンプルマクロの規模であっても、かなりの文字数を減らせることができていますので、プログラムの規模が大きくなればなるほど文字数の削減の効果は大きくなっていくと言えます。

Withでオブジェクトのプロパティやメソッドを連続して指定する

 Withステートメントでは、プロパティやメソッドを連続して指定ができます。

さきほどのサンプルコードでは、Withステートメントでシート1を参照しました。これでシート1のプロパティやメソッドについてコードの冒頭にピリオドをつけることで扱えるようになりました。

今度は、WithステートメントでA1セルを参照してみます。

シート1のA1セルをWithステートメントで参照したサンプルコード
  
Option Explicit

Sub withステートメント使用例3()
    
    'Withステートメントでこのブック(ファイル)のワークシートのA1セルのオブジェクトを参照する
    With ThisWorkbook.Worksheets(1).Range("A1")
    
        'ピリオドを書くだけでシート1のA1セルに対するメソッドやプロパティに対して指定ができる
        .Value = "A1セル" 'Valueプロパティで文字列を入力する
        .Interior.ColorIndex = 3 'Interiorプロパティ背景色を赤色にする
        .Copy 'Copyメソッドで文字列をコピーする
        .Offset(0, 1).PasteSpecial Paste:=xlPasteValues 'PasteSpecialメソッドとOffsetプロパティでA1セルの右隣のセルに貼り付ける

    End With
  Application.CutCopyMode = False'コピーモードを解除する

End Sub

A1セルをWithステートメントで参照して、メソッドやプロパティを以下のように指定しています。

  • Valueプロパティ
    A1セルに文字列”A1セル”を入力する指定をしています。
  • Interiorプロパティ
    A1セルの背景色を赤色にする指定をしています。
  • Copyメソッド
    A1セルをコピーする指定をしています。
  • PasteSpecialメソッド
    A1セルでコピーした値をB2セルに貼り付ける処理を指定しています。

Range(“A1”)セルのメソッドやプロパティを連続で指定して処理を実行できるね。

実行結果
withステートメント使用例3のマクロの実行結果画像

Withステートメントで参照したオブジェクトのメソッドやプロパティをまとめて処理できるね。

Withステートメントのネストや終了方法について

 Withステートメントは、別のWithステートメントのなかに配置することで入れ子(ネスト)にできます。

これは、オブジェクトの中にさらにオブジェクトがある場合に便利です。例えば、以下のコードでは、Rangeオブジェクトの中のFontオブジェクトに対してプロパティを指定しています。

Withステートメントを入れ子(ネスト)したサンプルコード
  
Option Explicit

Sub withステートメント使用例4()
    
    'Withステートメントでこのブック(ファイル)のワークシート1オブジェクトを参照する
    With ThisWorkbook.Worksheets(1)
    
        'Withステートメントを入れ子にしてA1セルオブジェクトを参照する
        With .Range("A1")
            .Value = "Withステートメントの(入れ子)ネスト" 'A1セルに文字を入力する
            
            'さらにWithステートメントを入れ子にしてFontオブジェクトを参照する
            With .Range("A1").Font
                .Bold = True'文字の太字にする

                .Color = vbYellow'文字色を黄色にする
                .Size = 12'文字の大きさを12にする
            End With 'Fontオブジェクトの参照を終了
        
        End With 'A1セルオブジェクトの参照を終了
    
    End With 'ワークシート1オブジェクトの参照を終了

 上記のように、Withステートメントを入れ子(ネスト)にする場合、外側のWithステートメントのなかに新たなWith~End Withを書きます。

 サンプルコードでは、ワークシート1を参照するためのWithステートメントのなかに、A1セルを参照したWithステートメントがあり、さらにそのなかにFontオブジェクトを参照して処理を実行しています。

 Withステートメントで指定したオブジェクトの参照を終了するタイミングは、End Withの実行までとなりますので、参照の順番とは逆にフォントオブジェクトの参照が終了、つぎにA1セルの参照が終了、さいごにシート1の参照が終了といったながれです。

Withステートメントを入れ子(ネスト)にしたイメージ
Withステートメントを入れ子(ネスト)にしたイメージ図

ネストすることでオブジェクトの中のオブジェクトを参照することができるね。

WithステートメントでApplicationオブジェクトのプロパティを設定する

 Withステートメントは、Applicationオブジェクトを参照することもできます。

 ApplicationオブジェクトとはExcelアプリケーションのことで、このオブジェクトは画面の更新、アラート通知、数式の計算方法の切り替えなど、マクロの動作を早くするための設定をもっているため、大規模なマクロを動作する直前や直後にまとめて設定すると良いでしょう。

Withステートメントで”Applicationオブジェクト”を参照してまとめて設定値を変更するコード
  
Option Explicit

Sub 処理前設定()

    With Application 'アプリケーションオブジェクトを参照(Excel)
        .ScreenUpdating = False '画面更新オフ
        .DisplayAlerts = False 'エラー通知オフ
        .Calculation = xlManual '自動計算オフ
    End With

End Sub

06行目

 画面の更新停止します。

 Falseにすることで編集した画面が描画されなくなります。大量の値を入力する場合など大きな処理で遅くなりそうな場面では、事前に設定しておくとマクロでの処理が速くなります。

07行目

 画面上に出す通知停止します。

 通知には既にファイルが開かれている場面で出るものや、編集後のファイルを終了するときの保存を促すものなどがありますが、マクロの処理が停止してしまうことを予防するために一時的に通知を出さないようにします。

08行目

 シート上にある数式の計算手動に変更します。

 シート上に書きこまれた数式の計算を手動(マニュアル)に変更します。自動のままだと常に計算される処理が実行されて余分な処理につかうリソースを省くことで処理が速くなります。

  
Option Explicit

Sub 処理後設定()

    With Application 'アプリケーションオブジェクトを参照(Excel)
        .ScreenUpdating = True '画面更新オン
        .DisplayAlerts = True 'エラー通知オン
        .Calculation = xlAutomatic '自動計算オン
    End With

End Sub

06行目

 画面の更新再開します。

 Trueにすることで編集した画面が描画されるようになります。ワークシートへの入力を処理を実行したあとに画面上に反映されるようにします。

07行目

 画面上に出す通知再開します。

 Trueにするとエラー通知などが表示されるようになります。Falseのままだと本来必要とする通知まで出さないようになってしまっているので停止と再開はセットで実行するように注意が必要です。

08行目

 シート上にある数式の計算自動に変更します。

 手動のままだとシートの上の関数などが計算されなくなるので、使用者が意図した結果を得られなくなったなどのトラブルを回避する上で元に戻すようにします。

Callで呼び出せるように、メインとは別のプロシージャで作っておくと便利だね。

Withステートメントでクラスオブジェクトのプロパティを設定する

Withステートメントは参照するオブジェクトを指定できることは解説しました。オブジェクトはブックやシート、セルなどがありますが、他にもクラスオブジェクトの参照ができます。

次に紹介するサンプルコードは、氏名・身長・体重を入力することで、BMIを計算し、計算結果のBMIによる判定をセルに出力するサンプルマクロです。ここでは、Withステートメントを使ってクラス内で宣言した変数に値を代入する処理をおこなっています。

Withはオブジェクトを参照できるなら、クラスもあつかえるってことだね。

まずは、出力するシートは以下のとおり。

Withステートメントでクラス内の変数に値を代入するサンプルコードを説明するためのシート

このサンプルエクセルシートに名前・身長・体重を入力して、BMIと判定結果を出力します。

このマクロのコードは以下のとおりです。

クラスモジュールのコード
  
Option Explicit

Public 氏名 As String
Public 身長 As Double
Public 身長M As Double
Public 体重 As Double
Public BMI As Double

氏名・身長・体重・BMIと、身長をメートル表示にした値を代入する変数をパブリック(Public)で宣言しています。

パブリック(Public)で宣言する理由は、標準モジュールからクラス内の変数に値を代入する処理ができるようにするためです。なお、ここではクラスモジュールのオブジェクト名は”身体情報“としています。

続いて、標準モジュールに書いたサンプルコードです。

標準モジュールのコード
  
Option Explicit

Sub 身体情報を入力する()

    Dim 情報入力 As 身体情報
    Set 情報入力 = New 身体情報
    
    'Withステートメントでクラスオブジェクト(身体情報)を参照する
    With 情報入力
        'クラス変数に数値を代入する処理
        .氏名 = Application.InputBox("氏名を入力してください", "情報入力", Type:=2)
        
        .身長 = Application.InputBox("身長をcmで入力してください", "情報入力", Type:=1)
        
        .身長M = Application.WorksheetFunction.RoundUp(.身長 / 100, 1)
        
        .体重 = Application.InputBox("体重をkgで入力してください", "情報入力", Type:=1)
        
        .BMI = .体重 / (.身長M * .身長M)
    End With 'クラスオブジェクト(身体情報)の参照を終了する
        
    'Withステートメントでシート名がSheet5を参照する
    With ThisWorkbook.Worksheets("Sheet5")
        '2行目から開始する
        Dim Row As Long: Row = 2
        
        '空白行でないなら、ひとつ下の行へ
        Do Until .Cells(Row, 1) = ""
            Row = Row + 1
        Loop
        
        '情報をセルに出力する
        .Cells(Row, 1) = 情報入力.氏名
        .Cells(Row, 2) = 情報入力.身長
        .Cells(Row, 3) = 情報入力.体重
        .Cells(Row, 4) = 情報入力.BMI
        
        'BMIから判定結果を出力する
        If .Cells(Row, 4) >= 5.5 And .Cells(Row, 4) <= 9.9 Then
            .Cells(Row, 5) = "低い"
            
        ElseIf .Cells(Row, 4) >= 10 And .Cells(Row, 4) <= 19.9 Then
            .Cells(Row, 5) = "標準"
            
        ElseIf .Cells(Row, 4) >= 20 And .Cells(Row, 4) <= 24.9 Then
            .Cells(Row, 5) = "やや高い"
        
        ElseIf .Cells(Row, 4) >= 25 Then
            .Cells(Row, 5) = "高い"
            
        End If
    
    End With 'Withステートメントでシート名がSheet5の参照を終了する

End Sub

05行目と06行目

クラスオブジェクトを変数として宣言しています。変数名は情報入力となります。

09行目

Withステートメントを使って、クラスオブジェクトである身体情報クラスを参照しています。

11行目・13行目・15行目・17行目・19行目

Application.InputBoxを使ってユーザーから入力された値を受け取り、それぞれの変数に代入しています。

23行目

Withステートメントを使って、シート5を参照しています。

25行目

入力する行を代入するための変数Rowを宣言します。

28行目から30行目

シート5のA列が空白になるまで行数を足していき、A列の空白行になるまで変数Rowに行数を代入します。

33行目から36行目

シート5のA列にクラス情報入力の氏名を入力します。
シート5のB列にクラス情報入力の身長を入力します。
シート5のC列にクラス情報入力の体重を入力します。
シート5のD列にクラス情報入力のBMIを入力します。

39行目、42行目、45行目、48行目

IFステートメントによる条件分岐処理によって、シート5のD列(BMI)の数値で低い標準やや高い高いの判定結果をE列に入力します。

サンプルマクロの実行結果(※10名分のデータを入力した状態)
Withステートメントでクラス内の変数に値を代入するサンプルコードを説明するためのシート(実行結果)

Withステートメントでクラスオブジェクトを参照して、それぞれの変数に値を代入することとシートへの出力ができました。

PR

残業はしたくない!PCやExcelのスキルアップであなたのプライベート時間を奪わせない!
実務をプロから学べる「ユースフル」の動画は永年見放題。Q&A機能で分からないを放置しないから安心。


詳しくは以下のリンクをクリック

VBAにおけるWithステートメントを使うときの注意点

Withステートメントを入れ子にするときは、以下の点に注意してください。

Withステートメントは必ずEnd Withステートメントで終了しなければなりません。
入れ子にした場合は、内側から順にEnd Withステートメントを記述します。

入れ子にしたWithステートメント内で、ピリオドから始まったコードは、直前(そのステートメントが含まれる最も内側)のWithステートメントで指定したオブジェクトのプロパティやメソッドとみなされます。

入れ子にしたWithステートメント内で、外側のWithステートメントで指定したオブジェクトのプロパティやメソッドにアクセスする場合は、完全修飾オブジェクト参照(すべての親オブジェクト名を含む)を指定する必要があります。

Withステートメントを入れ子にすると、コードの可読性が悪くなる可能性があるため、Withステートメントを入れ子(ネスト)にする場合は、変数などでオブジェクトを参照する方法などと比較してコードの書きかたを検討することをおすすめします。

例えば、以下のサンプルコードでは、シート1のA1セルからE4セルまでのセル範囲をWithステートメントで参照しています。

  
Option Explicit

Sub withステートメント使用例6()
        
    'Withステートメントでこのブック(ファイル)のワークシート1オブジェクトを参照する
    With ThisWorkbook.Worksheets(1).Range("A1:E4")
        .Value = 10 '範囲内のセルに10を入力する
        .Font.Size = 11 '範囲内のセルのフォントサイズを11にする
        .Font.Color = 0 '範囲内のセルのフォントカラーをクリアにする
        .Font.Bold = False '範囲内のセルの太字を通常に戻す
    End With 'ワークシート1オブジェクトの参照を終了

End Sub

このVBAコードを、オブジェクト変数をつかった参照に書きかえると以下となります。

  
Option Explicit

Sub 変数でセル範囲を参照したコード()
    
    'オブジェクト変数にセル範囲("A1:E4")を代入する
    Dim セル範囲 As Range: Set セル範囲 = ThisWorkbook.Worksheets(1).Range("A1:E4")
    
    セル範囲.Value = 10 '範囲内のセルに10を入力する
    セル範囲.Font.Size = 11 '範囲内のセルのフォントサイズを11にする
    セル範囲.Font.Color = 0 '範囲内のセルのフォントカラーをクリアにする
    セル範囲.Font.Bold = False '範囲内のセルを太字を戻す

End Sub

06行目

セル範囲を参照する変数としてセル範囲を宣言して、ワークシート1のA1セルからE4セル範囲を参照します。

08行目

セル範囲であるA1セルからE4セルに10を入力します。

09行目

セル範囲であるA1セルからE4セルのフォントサイズを11に変更します。

10行目

セル範囲であるA1セルからE4セルのフォントカラーをクリアします。

11行目

セル範囲であるA1セルからE4セルの太字を戻します。

どちらも同じ処理を実行するよ。

変数のとり扱い方については以下の記事で解説しています。変数の基本的な使い方について知りたい人は以下の記事もあわせてご覧ください。

Withステートメント内で変数や関数を使うときの注意点

Withステートメント内では、ピリオドから始まるステートメントは、Withで指定したオブジェクトのプロパティやメソッドとみなされます。しかし、変数や関数を使う場合は、ピリオドをつけないようにしてください。ピリオドをつけると、変数や関数がオブジェクトのメンバーとして解釈されてしまい、エラーになる可能性があります。

以下のサンプルコードでは、変数iや関数MsgBoxをWithステートメントの中で使っていますが、ピリオドをつけるとエラーが発生します。

  
Option Explicit

Sub withステートメント使用例7()
    
    Dim i As Long
    
    'Withステートメントでワークシート4のA1セルからE4セルまでの範囲を参照する
    With ThisWorkbook.Worksheets(4).Range("A1:E4")
    
        For i = 1 To .Count 'Withステートメントで参照した範囲内のセルの個数分(20)繰り返す
            MsgBox .Cells(i).Value'メッセージボックスで各セルに入力された値を表示する
        Next i
    
    End With 'ワークシート4オブジェクトの参照を終了

End Sub

08行目

Withステートメントでワークシート4のA1セルからE4セル範囲を参照します。

10行目

ForNext文をつかって繰り返し回数を指定していますが、.Conut ではWithステートメントで参照しているセル範囲のセルの数という意味です。参照しているA1からE4までのセルの個数は20であることから、変数iが1から20の間は処理を繰り返します。

実行結果としては、A1セルからE4セルに入力された値を順番にメッセージボックスに表示します。

Withステートメント内で変数や関数を使うときは、ピリオドをつけないように。

繰り返し文については、以下の記事でくわしく解説しています。For文以外の繰り返しの書きかたについても紹介していますので、あわせて参考にしてください。

Withで参照しているオブジェクトの位置や状態は変更しない

Withステートメントで参照しているオブジェクトの位置や状態が変わってしまうコードは書かないようにしましょう。なぜなら、あとからコード読むときに読み取れなくなってしまうからです。

では、位置や状態が変わってしまうケースを以下に紹介します。

サンプルのエクセルのシート1のA1 セルにA2セルにはそれぞれ文字が入力されています。

Withステートメントで注意すべきコードを説明するためのサンプル画像

上記のエクセルのA1セルをWithステートメントで参照したサンプルコード

  
Option Explicit

Sub withステートメント参照している位置や状態がかわるコード()
    
    'Withステートメントでこのブック(ファイル)のワークシート1のA1セルを参照する
    With ThisWorkbook.Worksheets("sheet1").Range("A1")
                   
        Debug.Print .Value 'A1セルの内容をイミディエイトウィンドウに出力する[1]
        
        'シート1の1行目に行を挿入する
        ThisWorkbook.Worksheets("sheet1").Rows(1).Insert
        
        Debug.Print .Value 'A1セルの内容をイミディエイトウィンドウに出力する[2]
        
        'シート1の1列目に列を挿入する
        ThisWorkbook.Worksheets("sheet1").Columns(1).Insert
        
        Debug.Print .Value 'A1セルの内容をイミディエイトウィンドウに出力する[3]
        
        'シート1のA1セルの入力された文字を削除する
        ThisWorkbook.Worksheets("sheet1").Range("A1").ClearContents
        
        Debug.Print .Value 'A1セルの内容をイミディエイトウィンドウに出力する[4]
        
    End With 'ワークシート1オブジェクトの参照を終了

End Sub

06行目

Withステートメントでワークシート1のA1セルを参照します。

08行目

Debug.Print .Valueの”.Value”はA1セルに入力されている値を返します。ここではデバッグプリントを利用しているため結果をイミディエイトウィンドウに表示します。

11行目

Insert メソッドで行(Row)を挿入します。この処理が実行されるとA1セルがA2セルになります。

13行目

Debug.Print .Valueの”.Value”は参照当初のA1セルに入力されている「これはA1セルです。」を返します。11行目で行を挿入したことで参照しているセルがズレてしまっていますので、この時点のシート上のA1セルは空白となりますが結果としては参照した時点のものです。

16行目

Insert メソッドで行(Column)を挿入します。この処理が実行されると最初A1セルであったものがB2セルになります。(11行目でA2セルとなっていることから、行も挿入されています。)

18行目

Debug.Print .Valueの”.Value”は参照当初のA1セルに入力されている「これはA1セルです。」を返します。11行目と16行目で行と列を挿入したことで参照しているセルがズレてしまっていますので、この時点のシート上のA1セルは空白となりますが結果としては参照した時点のものです。

21行目

ClearContentsメソッドでA1セルに入力されている値の削除をします。11行目や16行目で行や列がズレているため、最初から空白ですが、Withステートメントで参照しているセルの値が消されるのかを検証するために実行しています。

23行目

Debug.Print .Valueの”.Value”は参照当初のA1セルに入力されている「これはA1セルです。」を返します。11行目と16行目、21行目で行、列の挿入と値の削除を処理したことで、この時点のシート上のA1セルは空白となりますが結果としては参照した時点のものです。

これはA1セルです。
これはA1セルです。
これはA1セルです。
これはA1セルです。

 Withステートメントで参照しているオブジェクトはA1セルですが、13行目の出力時は行が挿入されて元はA1セルであったセルはA2セルになっています。さらに18行目の出力時は列も挿入されているためB2セルに変わったとしても、結果は変わらず「これはA1セルです。」を表示します。

 この結果から、Withステートメントの参照は、参照を開始した時点でのA1セルを参照していると言えます。その証拠に、このプロシージャをもう一度実行した場合は、新たなA1セルを参照しており、1度目のマクロの実行で行や列が追加されておりA1セルには何も入力されていないため、イミディエイトウィンドウに空白が返ってきます。

Withで参照しているオブジェクトの位置や状態を変更することはなるべく控える

 理由としては、コードからどこを参照しているのかを読みとることが難しくなるためです。

 プログラムのコードは自分以外の人がコードを読むことや、コードを作成した時期から相当な日数が経過したあとであっても、不具合が見つかったときや、機能の拡張で過去に書いたコードを改めて理解する必要が出てくることが一般的です。そのため、可読性が悪くなることは改めてコードを理解するときのハードルが高くなるからです。

 Withステートメントを使う効果がそもそも可読性を上げる、つまり読みやすくすることであるとすれば、Withステートメントで参照している位置や状態が変わってしまうことは、本来の目的とは裏腹な結果になってしまいます。

 これらを考えた場合、Withステートメントで参照しているオブジェクトをWithのなかで参照先を移動、状態を変更することはできるだけ避けたほうが良いでしょう。

Withステートメントを使いすぎるとコードが読みにくくなる可能性

Withステートメントを使うと、コード量がスリムになり、同じオブジェクトを記述する必要もなくなるためコードの入力も楽になります。しかし、Withステートメントを使いすぎることで、かえってコードが読みにくくなる場合があります。

特に、以下のような場合は注意が必要です 。

  • Withステートメントを入れ子(ネスト)にする場合
  • Withステートメント内で複数の異なるオブジェクトを操作する場合
  • Withステートメント内でオブジェクトの位置や状態を変更するようなコードを書く場合

これらの場合は、Withステートメントを多用せずに、それぞれのオブジェクト名を明示的に書き込んだ方が読み取りやすくなります。またWithステートメント以外の参照方法として、指定のオブジェクトを変数に代入する書きかたを選択した方が可読性や安全性は良くなります。

VBAのWithステートメントに関する記事まとめ

本記事では、エクセルVBAにおけるWithステートメントで特徴と使い方について解説しました。Withステートメントをうまく使うことでVBAのコードを書くボリュームを減らすことができ、可読性が良くなる効果が期待できます。

また、WithステートメントはWithステートメント中にさらにWithステートメントを書きこむことで入れ子(ネスト)にできますが、多用することで逆効果として可読性が下がってしまう点には注意が必要です。

それでは、本記事のさいごにWithステートメントについてまとめていきます。

Withステートメントの利用方法と注意点

Withステートメントは、VBAでオブジェクトのプロパティやメソッドを連続して指定するときに便利な書きかたであり、使い方次第でコードの記述量を大きく減らすことができます。しかし、Withステートメントを扱うときには、いくつかの注意事項を意識しておく必要があります。

以下にWithステートメントの利用方法と注意点をまとめます。

どのオブジェクトを参照しているかが分かりにくくなってしまうのなら使用は控えようね。

以上、エクセルVBAでWithステートメントの利用方法と注意点の解説をしました。プログラミングでは、大規模で複雑な処理であってもシンプルで読みやすいコードで実装できることが、スキルアップにつながります。

今回紹介したWithステートメントも、使い方次第ではコード量を減らす効果はありますので、効率よくコードが書けるようになります。ただし、適切な使用方法での運用でなければ、コードを書く文字量は減らせても、プログラム全体の可読性が低下し、何をしているのかわかりにくいコードとなってしまうことに注意が必要です。

Withステートメントを適切に使うことが、マクロ開発者としてのスキルが向上するものだと覚えておくと良いでしょう。

今回はここまで。

コダマのもりブログはにほんブログ村に登録しています。
ブログの記事が役に立ったと感じて頂けたら、フォローお願いいたします。

コメント

タイトルとURLをコピーしました