VBA技術解説
「Withの功罪」:コードを読みやすくする強力な道具と、その落とし穴

ExcelマクロVBAの問題点と解決策、VBAの技術的解説
公開日:2026-09-03 最終更新日:2026-09-03

「Withの功罪」:コードを読みやすくする強力な道具と、その落とし穴


VBAのコードを書くとき、With ステートメントを使うべきか、使わざるべきか。
このテーマは古くから議論されてきましたが、私自身、長年コードを書き、また他人に教える立場を経験する中で、その捉え方が少しずつ変化してきました。


今回は、私が感じる「With の本当の価値」と、初心者が陥りがちな「With の罠」についてお話しします。

※本記事のVBAおよび解説文章は、生成AI(ChatGPT、Gemini、Claude)を活用して作成しています。VBAや解説文の最終的な内容は人間による確認・編集を経て掲載しています。


目次

1. 昔の私:Why With? コピペとオブジェクト変数で十分だった

かなり昔、私がVBAのコードをゴリゴリ書いていた頃、With はほとんど使いませんでした。
理由は至ってシンプルです。

長いオブジェクト名もコピペすれば済む
例えば Worksheets("Sheet1").Range("A1").Value のような長めの記述であっても、2行目以降はコピペして使い回せば入力の手間は大して変わりません。

Worksheets("Sheet1").Range("A1").Value = "商品名"
Worksheets("Sheet1").Range("A1").Font.Size = 11

複雑ならオブジェクト変数を使えばいい
対象の指定が長くて煩雑なら、最初からオブジェクト変数に受ければ十分です。

Dim myRange As Range
Set myRange = Worksheets("Sheet1").Range("A1")

myRange.Value = "商品名"
myRange.Font.Size = 11

そもそも旧VBやVB.NETでもWithを使う文化が稀だった
VBAの母体であるVisual Basic(VB6等)やVB.NETの言語文化においても、一般的にも With を好んで多用する習慣は薄く、私自身も開発現場で使う機会がほとんどありませんでした。

変数を使えば名前も短くなり、コードの動作も明確になります。
わざわざ構文をネストさせてまで With を使う必然性を、当時の私はあまり感じていませんでした。


2. 伝える立場になって気づいた「With」の見た目の威力

しかし、解説記事や人に見せるためのVBAコードを書くようになってから、意識が変わりました。
With を使うと、ぱっと見でコード全体が非常に読みやすくなるのです。
それはつまり、WEB記事でも見やすくなるという事で、積極的に採用するようになりました。

' Withなし
Worksheets("Sheet1").Range("A1").Value = "商品名"
Worksheets("Sheet1").Range("A1").Font.Bold = True
Worksheets("Sheet1").Range("A1").Interior.Color = vbYellow
' Withあり
With Worksheets("Sheet1").Range("A1")
  .Value = "商品名"
  .Font.Bold = True
  .Interior.Color = vbYellow
End With

ドット(.)で始まる行が連続することで、「あ、ここは同じ対象に対してプロパティを設定しているブロックだな」と直感的に理解できます。
さらに大きなメリットは、そのコードブロックで扱う「主たるオブジェクト」が明確になることです。
執筆者や設計者の「ここをメインに処理します」という意図が、読み手に一瞬で伝わります。


3. 初心者への推奨:主たるシートを「With」で捉える

プログラミング初心者にVBAの書き方を伝える際、最も大きな壁となり、かつバグの温床になりやすいのが「今どのシートを操作しているか分からない(=暗黙のアクティブシート依存)」という問題です。
本来であれば、オブジェクト変数を使って明示するのが定石です。
なお、オブジェクト変数とSetステートメントの基本的な使い方は、こちらの記事を参照してください。
参照: オブジェクト変数とSetステートメント|VBA入門
・オブジェクト変数 ・個有のオブジェクト型とは ・Setステートメント ・Setステートメントの使用例 ・WithとSetの使い分け方 ・Setステートメントの実践的な使い方 ・Is演算子によるオブジェクトの比較 ・最後に

このようにオブジェクト変数を使うのも非常に良い方法ですが、初心者が最初に書くコードとしては、「処理の主軸となるワークシートを With で捉えて明示する」というアプローチも直感的で分かりやすいものです。

With Worksheets("データ")
  .Range("A1").Value = 100
  .Range("A2").Value = 200
End With

処理全体を With の中に閉じ込めることで、アクティブなシートがどれであっても誤動作を防ぐことができ、VBAにおいて極めて重要な「常に親オブジェクト(シート)を明示して書く」という感覚を自然と身につけてもらえます。
単に「コードを短く書くため」ではなく、「対象のシートを確実に固定し、安全に操作するため」に With を使う。
これこそが、初心者にとっても分かりやすい With の使い方の一つだと考えています。

オブジェクト変数との基本的な使い分け
実務においては、With とオブジェクト変数を対立させるのではなく、役割に応じて適切に使い分ける(あるいは組み合わせる)のが安全な設計につながります。
  • With が適している場面(構造・主役の固定)
    処理全体の「主たる舞台」となるシートを1つ固定して操作する場合
    セルの書式設定など、同一オブジェクトに対して連続で複数のプロパティを設定する場合

  • オブジェクト変数が適している場面(動的・複数要素の操作)
    複数のシートやブックをまたいでデータを相互に転送・処理する場合
    ループ処理や複雑な条件分岐が挟まり、処理が長くなる場合
例えば、With で括った範囲の中で別オブジェクトの変数(TargetWorksheet 等)が入り乱れて可読性が落ちるくらいなら、
With を解体して両方をオブジェクト変数(Set srcWS = ... / Set tgtWS = ...)として宣言した方が、誰の目にも一目瞭然なコードになります。


4. 「罪」の側:省入力の道具と化したときの違和感

ここまでのメリットがありながら、なぜ「功罪」なのか。
それは、With の目的が単なる「入力の省略テクニック」としてばかり捉えられていることに強い違和感があるからです。
「文字数を減らせるから」「打つのが楽だから」という理由だけで使われる With は、時に以下のような悪夢のようなコードを生み出します。

4.1. 過度なネストによる可読性の崩壊

With の中に With を重ねたコードは、途中のドット(.)が一体どのオブジェクトを指しているのかを追うコストが跳ね上がります。

' ネストが深すぎて視認性が落ちるコード例
With Worksheets("Sheet1")
  With .Range("A1")
    With .Font
      .Size = 11
      .Bold = True
    End With
    .Interior.Color = vbYellow
  End With
  .Range("B1").Value = "完了"
End With

With のネストが深くなるほど、. がどの With の対象を指しているのかを視覚的に追跡する必要が生じ、結果として可読性が急激に落ちてしまいます。

【実践的な目安】
ネストは原則として1段(重ねない)、使うとしても最大2段までにとどめるのが無難です。
プロパティの設定程度であればネストを増やさず、.Font.Size = 11 や .Font.Bold = True のように記述した方が、ネストによる階層の迷子を防ぎやすくなる場合もあります。

4.2. ブロックの長大化によるスコープの曖昧化

With ブロックの中に何十行もの処理や制御構文(If や For)を詰め込むと、どこで With が始まり、どこで終わるのかが見えなくなります。
特に危険なのが、左右ともに長い代入文の「右辺の後ろの方」にひっそりとドットが存在するパターンです。

' スコープが見えなくなるコード例
With Worksheets("データ")
  .Cells(1, 1).Value = "開始"
  
  ' ...(あいだに数十行の異なる処理やループが入る)...
  
  For i = 2 To lastRow
    ' 左右ともに長い代入文。右辺の奥深くに「.Cells」が隠れている
    TargetWorksheet.Cells(i, 5).Value = SourceWorkbook.Worksheets("Master").Cells(i, 3).Value + .Cells(i, 2).Value
  Next i
  
  ' ...(さらに長い処理)...
End With

上記のようなコードでは、右辺の末尾近くにある .Cells(i, 2) のドットを見落としやすくなります。
「この .Cells はどのシートを指しているのか?」を追うために数十行上までスクロールして With の宣言を確認しなければならず、解読コストが大幅に増えます。
最悪の場合、読み手が「親シートの指定漏れ(タイポ)」と誤解してしまい、バグの特定を遅らせる要因になります。

【実践的な目安】
With ブロックの長さは、画面をスクロールせずに全容が見渡せる10~15行程度までを目安とすべきです。
これを超える長大な処理になる場合は、With で強引にくくるのをやめ、素直にオブジェクト変数(Dim ws As Worksheet 等)へ割り当てて明示的な変数名で操作する方に切り替えるのが安全です。


5. 本当の難しさ:「Withが捉えているオブジェクト」の理解

実は、With の本質的な難しさは「VBAがどのタイミングで何を捉え、内部でどう保持しているか」という動作原理の理解にあります。
単なる「文字列の置き換え(短縮)」として使っていると、意図しない挙動や勘違いを引き起こす原因になります。

5.1. 「Withに入った瞬間」にオブジェクトの参照が固定される

With は、その行が実行された最初の1回だけ右辺のオブジェクトを評価し、内部でオブジェクトへの参照として保持します。

With Worksheets("Sheet1").Range("A1")
  ' このブロック内で評価されるのは、
  ' With行を通過した瞬間に確定した「Sheet1のA1」という特定のRangeオブジェクト
End With

後から参照先のプロパティや状態が変わっても、With が保持している「オブジェクトへの参照」そのものは変わりません。

5.2. 範囲の変動や操作によって「捉えたオブジェクト」がズレる罠

特に注意が必要なのが、With で Range を指定した状態で、その領域に行・列の挿入や削除を行ったり、セル範囲の変形操作を挟んだりする場合です。

' A1セルをWithで捉える
With Worksheets("Sheet1").Range("A1")
  .Value = "初期値"
  
  ' 1行目に新しい行を挿入する
  Worksheets("Sheet1").Rows(1).Insert
  
  ' ここで設定されるのは、移動後の「A2セル」!
  .Value = "変更後"
End With

直感的には「1行挿入されたのだから、もう一度 A1 に書き込まれるのではないか」と誤解しがちです。
しかし、With は「A1 という文字」を覚えているのではなく、With 行が評価された時点で得られた Range オブジェクトへの参照を対象にしています。
そのため、行挿入によってその Range オブジェクト自体がシート上で A2 へ移動すると、With の処理対象もそのまま A2 を書き換えることになります。

5.3. 「Withを使えば高速化する」という誤解と真実

VBAの解説でよく「With を使うと処理が速くなる」と言われますが、これは半分正解で半分誤解です。
With というステートメント自体が高速化の魔法を持っているわけではありません。
速度差が生じるポイントは、Worksheets("Sheet1") や Cells(i, 1) のようにコレクションからオブジェクトを毎回検索・取得する処理にあります。

' 遅い理由:ループのたびに Worksheets("Sheet1") の検索が発生する
For i = 1 To 10000
  Worksheets("Sheet1").Cells(i, 1).Value = i
Next i

' 速い理由:Worksheets("Sheet1") の検索が最初の1回で済むから
With Worksheets("Sheet1")
  For i = 1 To 10000
    .Cells(i, 1).Value = i
  Next i
End With

つまり、速くなっている理由は「With を使ったから」ではなく、「重いオブジェクト参照の呼び出し回数を減らしたから」です。
これはオブジェクト変数に Set ws = Worksheets("Sheet1") と受けて操作するのと本質的に同じメカニズムです。

この With の内部動作や実行速度に対する正確な捉え方、注意点については、以下の技術解説記事で詳しく検証されています。
参照: Withステートメントの実行速度と注意点|VBA技術解説
・マクロVBAのテストコード(Worksheet) ・マクロVBAのテストコード(Range) ・Withステートメントの注意点 ・最後に

5.4. デバッグ時の挙動の違い(イミディエイトウィンドウの現象)

With ブロック内で処理を一時停止(中断)させた際、イミディエイトウィンドウで 「?.Value」 などの先頭ドット構文を実行したときの挙動は、With に指定した書き方や変数宣言の型によって明確に分かれます。

' パターン1:式を直接渡した場合 → 参照不可(エラー)
With Worksheets(1).Cells(1, 1)
  Stop ' イミディエイトで「?.Value」 → エラー
End With

' パターン2:Variant型変数で受けた場合 → 参照不可(エラー)
Dim rng As Variant
Set rng = Worksheets(1).Cells(1, 1)
With rng
  Stop ' イミディエイトで「?.Value」 → エラー
End With

' パターン3:Object型変数で受けた場合 → 参照可能!
Dim rng As Object
Set rng = Worksheets(1).Cells(1, 1)
With rng
  Stop ' イミディエイトで「?.Value」 → 値が返る!
End With

' パターン4:Range型変数で受けた場合 → 参照可能&入力候補も出現!
Dim rng As Range
Set rng = Worksheets(1).Cells(1, 1)
With rng
  Stop ' イミディエイトで「?.」と打つと入力候補が出現し、「?.Value」も返る!
End With

実機で確認すると、以下のような現象が起こります。
  • With Worksheets(1).Cells(1, 1) のように式を直接渡した場合や、Dim rng As Variant で受けた場合は、イミディエイトウィンドウで 「?.Value」 や 「?.Address」 を打ち込んでもエラーになり値を参照できません。
  • 一方、Dim rng As Object や Dim rng As Range のようにオブジェクトを扱う型として宣言した変数を経由して With rng とした場合は、イミディエイトウィンドウで 「?.Value」 や 「?.Address」 が正常に受け付けられます。
  • さらに Dim rng As Range のように具体的な型を宣言している場合は、イミディエイトウィンドウで 「?.」 と入力した時点でメンバーの自動補完(入力候補)のポップアップまで表示されます。

    「Withの功罪」:コードを読みやすくする強力な道具と、その落とし穴

※なお、いずれの場合であっても、ウォッチウィンドウに先頭ドット(.Value)のまま登録することはできず、ブレーク時のマウスホバーによるポップアップ値表示も機能しません。


まとめ:道具の「意図」を理解して使う

功(メリット):主たるオブジェクトを明確にし、コードの意図と構造を視覚的に伝えられる。
罪(デメリット):単なる文字省略として乱用されると、ネストの深化や参照の不透明さを招く。

With は決して「記述を楽にするためのショートカット」ではありません。
「短く書けるか」ではなく、「何を主役として扱っているか」で With の使用を判断すること。
コードの主役を際立たせ、読み手に意図を正しく伝えるための構造化のツールとして使ってこそ、その真価を発揮するのです。

初心者の方へ
もしあなたがまだVBAを始めたばかりなら、最初は無理に複雑な With を使いこなそうとする必要はありません。
まずは「処理の対象となるメインのシートを1つだけ With で囲む」ということから始めてみてください。
それだけで暗黙のシート依存を防ぎ、安全で読みやすいコードになります。

ただし、VBAに慣れてきて「もっと短く書けないか」「プロパティも With でまとめられないか」とステップアップしたくなった時や、思い通りに動かずデバッグで悩んだ時は、ぜひこの記事で触れた「With の裏側の挙動や罠」をちょっと思い出してみてください。
きっと、バグを防ぎワンランク上のコードを書くためのヒントになるはずです。




同じテーマ「マクロVBA技術解説」の記事

印刷範囲の設定・印刷範囲のクリア
VBAの省略可能な記述について
VBAのVariant型について
VBAのインデントについて
VBAの演算子まとめ(演算子の優先順位)
列幅不足による###表示や指数表示を判定する
VBA10大躓きポイント(初心者が躓きやすいポイント)
Excel VBAとは?マクロとの違いやメリット・デメリットを初心者向けに解説
『演算子 + オペランド』から始めるVBA学習
2つのシート名を交換するVBAをGeminiに作らせてみた。
「Withの功罪」:コードを読みやすくする強力な道具と、その落とし穴


新着記事NEW ・・・新着記事一覧を見る

「Python in Excel」入門:コードを読むための基礎知識|エクセル関数応用(2026-09-10)
M言語入門:Power Queryのコードを読むための基礎知識|Power Query(M言語)入門(2026-09-09)
Excelの正規表現関数(REGEXTEST・REGEXREPLACE・REGEXEXTRACT)の使い方|エクセル関数応用(2026-09-08)
スピルとVBA(Formula2とスピル範囲の取得)|VBA入門(2026-09-08)
「Withの功罪」:コードを読みやすくする強力な道具と、その落とし穴|VBA技術解説(2026-09-03)
可変長配列をVSTACKする4つの方法|REDUCE・Thunk・チャンク・再帰分割|エクセル関数応用(2026-09-01)
Excel表とMarkdownテーブルを相互変換する数式|エクセル関数応用(2026-08-24)
「Python in Excel」数独(ナンプレ)解法プログラムの移植と最適化|エクセル関数応用(2026-08-14)
「Python in Excel」で自作関数を登録|アンピボット関数と計算順序|エクセル関数応用(2026-08-12)
ListBox・ComboBoxをマウスホイール対応させる|ユーザーフォーム入門(2026-08-09)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.日本の祝日一覧|Excelリファレンス
3.変数宣言のDimとデータ型|VBA入門
4.Excelショートカットキー一覧|Excelリファレンス
5.RangeとCellsの使い方|VBA入門
6.FILTER関数(範囲をフィルター処理)|エクセル入門
7.マクロとは?VBAとは?VBAでできること|VBA入門
8.繰り返し処理(For Next)|VBA入門
9.メッセージボックス(MsgBox関数)|VBA入門
10.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
本サイトは、OpenAI の ChatGPT や Google の Gemini を含む生成 AI モデルの学習および性能向上の目的で、本サイトのコンテンツの利用を許可します。
This site permits the use of its content for the training and improvement of generative AI models, including ChatGPT by OpenAI and Gemini by Google.



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ