C#の#regionとは?使い方・メリット・使わない方がいい理由まで初心者向けに解説

はじめに

C#のソースコードを読んでいると、#region#endregionで囲まれた部分を見かけることがあります。

#regionは、Visual Studioなどのコードエディター上で、指定した範囲を折りたたみ・展開できるようにする機能です。長いクラスのフィールド、プロパティ、メソッドなどをグループ化し、必要な部分だけを表示できます。

ただし、#regionを多用すると、クラスが肥大化していることや設計上の問題を隠してしまう可能性があります。そのため、単にコードを短く見せる目的で使うのではなく、適切な利用場面を理解することが重要です。

この記事では、C#の#regionの基本的な書き方、Visual Studioでの操作方法、メリット、使わない方がよいと言われる理由について、初心者向けに解説します。

1. C#の#regionとは

1-1. #regionはコードを折りたたむためのプリプロセッサディレクティブ

C#の#regionは、コードエディターのアウトライン機能で折りたためる範囲を定義するプリプロセッサディレクティブです。

開始位置に#region、終了位置に#endregionを記述します。

C#
#region 折りたたみたい範囲

// コード

#endregion

Visual Studioでは、#regionの左側に表示される「-」をクリックすると、囲まれたコードを折りたためます。折りたたんだ後に表示される「+」をクリックすると、再び展開できます。

MicrosoftのC#リファレンスでも、#regionはアウトラインで折りたためるコード領域を開始し、#endregionはその領域を終了するディレクティブとして説明されています。Microsoft Learn

なお、一般的には「リージョン」と読みます。

1-2. #regionでできること

#regionを使うと、主に次のようなことができます。

  • 関連するメソッドをまとめる

  • フィールドとプロパティを分類する

  • インターフェースの実装部分をまとめる

  • イベント処理をひとまとまりにする

  • 自動生成されたコードを折りたたむ

  • 現在編集していないコードを一時的に隠す

たとえば、ユーザー情報を扱うクラスに「フィールド」「プロパティ」「メソッド」というリージョンを作れば、クラス内の構成を視覚的に把握しやすくなります。

C#
public class User
{
#region フィールド

private string _name;
private int _age;

#endregion

#region プロパティ

public string Name
{
get => _name;
set => _name = value;
}

public int Age
{
get => _age;
set => _age = value;
}

#endregion

#region メソッド

public void ShowProfile()
{
Console.WriteLine($"{Name}:{Age}歳");
}

#endregion
}

ただし、#regionはコードそのものを削除したり、処理を無効化したりする機能ではありません。あくまでエディター上の表示を整理するための機能です。

1-3. #regionがコードの実行結果に与える影響

#region#endregionは、プログラムの実行結果に影響を与えません。

次の2つのコードは、実行時には同じ動作をします。

C#
#region あいさつ処理

Console.WriteLine("こんにちは");

#endregion
C#
Console.WriteLine("こんにちは");

#regionは、変数、条件分岐、メソッド呼び出しなどの実行可能な命令ではありません。コンパイル対象のコードを条件によって切り替える#if#elseとも役割が異なります。

たとえば、次の#ifはコンパイルされるコードを変更します。

C#
#if DEBUG
Console.WriteLine("デバッグモードです");
#endif

一方、次の#regionは表示上の範囲を作るだけです。

C#
#region デバッグ関連

Console.WriteLine("デバッグ情報を出力します");

#endregion

#regionを削除しても、その内側にあるC#コードが同じであれば、基本的にプログラムの動作は変わりません。

1-4. Visual Studioで#regionを使う場面

Visual Studioでは、長いソースファイルの一部を折りたたみ、現在作業しているコードに集中したい場面で#regionが使われます。

代表的な利用例は次のとおりです。

C#
#region コンストラクター
#endregion

#region 公開プロパティ
#endregion

#region 公開メソッド
#endregion

#region 非公開メソッド
#endregion

ほかにも、インターフェースごとに実装をまとめる使い方があります。

C#
#region IDisposableの実装

public void Dispose()
{
// リソースの解放処理
}

#endregion

Windows FormsやWPFなどでは、イベントハンドラーを機能単位で整理する目的でも使われます。

C#
#region ボタンイベント

private void SaveButton_Click(object sender, EventArgs e)
{
Save();
}

private void CancelButton_Click(object sender, EventArgs e)
{
Close();
}

#endregion

2. C#で#regionを使う基本的な書き方

2-1. #regionと#endregionの基本構文

#regionを使う場合は、必ず対応する#endregionを記述します。

C#
#region

// 折りたたむコード

#endregion

#regionだけを書いて#endregionを書かなかった場合、リージョンを正しく終了できません。

C#
#region メソッド

public void Execute()
{
Console.WriteLine("実行");
}

// #endregionがない

基本的には、次のように開始と終了をセットで記述します。

C#
#region メソッド

public void Execute()
{
Console.WriteLine("実行");
}

#endregion

#region#endregionはコメントではありません。先頭に//を付けると、リージョンとして認識されなくなります。

C#
// #region メソッド
// #endregion

2-2. リージョン名を付ける方法

#regionの後ろには、リージョン名を付けられます。

C#
#region 公開メソッド

public void Start()
{
}

public void Stop()
{
}

#endregion

折りたたむと、リージョン名がエディター上に表示されます。そのため、「処理」「その他」のような曖昧な名前ではなく、含まれているコードが分かる名前を付けることが大切です。

よい例は次のとおりです。

C#
#region 注文の検証処理
#endregion

#region ファイル読み込み処理
#endregion

#region IComparableの実装
#endregion

内容を判断しにくい名前は避けましょう。

C#
#region いろいろ
#endregion

#region その他
#endregion

#region 処理
#endregion

リージョン名は日本語でも英語でも構いません。チーム開発では、プロジェクト内で表記ルールを統一すると読みやすくなります。

2-3. メソッドを#regionで囲むサンプル

関連するメソッドを#regionでまとめる例を見てみましょう。

C#
public class Calculator
{
#region 基本計算

public int Add(int x, int y)
{
return x + y;
}

public int Subtract(int x, int y)
{
return x - y;
}

#endregion
}

この例では、加算と減算を行うメソッドを「基本計算」というリージョンにまとめています。

メソッドを機能別に分けることもできます。

C#
public class UserService
{
#region ユーザー検索

public User? FindById(int id)
{
return null;
}

public User? FindByEmail(string email)
{
return null;
}

#endregion

#region ユーザー更新

public void UpdateName(int id, string name)
{
}

public void UpdateEmail(int id, string email)
{
}

#endregion
}

ただし、リージョンが必要になるほど多数の機能が1つのクラスに集まっている場合は、クラスを分割できないか検討する必要があります。

2-4. フィールドやプロパティを#regionで整理するサンプル

フィールドやプロパティを種類ごとに整理することもできます。

C#
public class Product
{
#region フィールド

private string _name = string.Empty;
private decimal _price;

#endregion

#region プロパティ

public int Id { get; set; }

public string Name
{
get => _name;
set => _name = value;
}

public decimal Price
{
get => _price;
set => _price = value;
}

#endregion
}

このような分類は、メンバー数が多いクラスでは目的のコードを探す助けになります。

一方、メンバーが数個しかない小さなクラスでは、リージョンを追加することで記述量が増え、かえって読みにくくなる場合があります。

C#
public class Product
{
public int Id { get; set; }

public string Name { get; set; } = string.Empty;

public decimal Price { get; set; }
}

小さなクラスであれば、リージョンを使わず、そのまま記述した方が構造を把握しやすいでしょう。

2-5. 複数の#regionを使うサンプル

1つのクラス内で複数の#regionを使うこともできます。

C#
public class OrderService
{
#region フィールド

private readonly OrderRepository _repository;

#endregion

#region コンストラクター

public OrderService(OrderRepository repository)
{
_repository = repository;
}

#endregion

#region 公開メソッド

public void CreateOrder()
{
ValidateOrder();
_repository.Save();
}

#endregion

#region 非公開メソッド

private void ValidateOrder()
{
// 検証処理
}

#endregion
}

各リージョンは独立しているため、必要な部分だけを展開できます。

ただし、「フィールド」「コンストラクター」「公開メソッド」「非公開メソッド」のような分類をすべてのクラスに機械的に追加する必要はありません。コード量が少ない場合は、通常のメンバー順だけで十分です。

2-6. #regionを入れ子にする方法

#regionの中に別の#regionを記述し、入れ子にすることもできます。

C#
#region データ操作

#region 読み込み処理

public void Load()
{
Console.WriteLine("読み込み");
}

#endregion

#region 保存処理

public void Save()
{
Console.WriteLine("保存");
}

#endregion

#endregion

Visual Studioでは、外側の「データ操作」を折りたたむと、内側の「読み込み処理」と「保存処理」もまとめて非表示になります。

入れ子にする場合は、開始と終了の対応関係が分かるように記述しましょう。

C#
#region 外側

#region 内側

// コード

#endregion

#endregion

リージョンの入れ子は利用できますが、階層が深くなると目的のコードを探しにくくなります。通常は1階層程度に抑え、何段もの入れ子が必要ならクラス分割を検討するのがおすすめです。

また、#region#ifの範囲を途中で交差させることはできません。どちらかをもう一方の内側に完全に収める必要があります。Microsoft Learn

3. Visual Studioで#regionを折りたたむ・展開する方法

3-1. マウス操作で折りたたむ・展開する手順

Visual Studioで#regionを記述すると、コードエディター左側のアウトライン領域に折りたたみ用の記号が表示されます。

操作手順は次のとおりです。

  1. #region#endregionでコードを囲む

  2. #regionの左側に表示される「-」をクリックする

  3. リージョンが1行に折りたたまれる

  4. 表示された「+」をクリックして展開する

たとえば、次のコードがあるとします。

C#
#region 計算処理

public int Add(int x, int y)
{
return x + y;
}

#endregion

折りたたむと、エディター上では「計算処理」というリージョン名を中心とした短い表示になります。

折りたたまれた部分にマウスポインターを合わせると、内部のコードをツールチップで確認できる場合もあります。Visual Studioの公式ドキュメントでも、アウトライン領域の記号を使った展開・折りたたみや、ツールチップによる内容確認が案内されています。Microsoft Learn

3-2. ショートカットキーで操作する方法

Visual Studioでは、キーボードショートカットでもアウトラインを操作できます。

現在カーソルがあるリージョンを折りたたむ、または展開する標準ショートカットは次のとおりです。

Ctrl + M
続けて
Ctrl + M

2つのキーを同時に押し続けるのではなく、Ctrl + Mを押した後、もう一度Ctrl + Mを押します。

主なアウトライン操作は次のとおりです。

操作標準ショートカット
現在の領域を折りたたむ・展開するCtrl + M, Ctrl + M
すべてのアウトラインを切り替えるCtrl + M, Ctrl + L
定義部分まで折りたたむCtrl + M, Ctrl + O
アウトライン機能を停止するCtrl + M, Ctrl + P

これらはVisual Studioの標準的なキー設定です。使用しているキーボードマッピングやカスタマイズによって異なる場合があります。Microsoft Learn+1

ショートカットが反応しない場合は、Visual Studioのメニューから次の設定を確認します。

ツール
→ オプション
→ 環境
→ キーボード

3-3. ファイル内の#regionを一括で折りたたむ方法

ファイル内のアウトラインをまとめて操作するには、次のショートカットを使用します。

Ctrl + M, Ctrl + L

メニューから操作する場合は、Visual Studioの「編集」から「アウトライン」を開き、「すべてのアウトラインの切り替え」に相当するコマンドを選択します。

注意点として、Ctrl + M, Ctrl + Lは「必ずすべてを折りたたむ」専用操作ではなく、すべてのアウトライン状態を切り替える操作です。一部が展開、一部が折りたたまれている状態では、まず展開側にそろうことがあります。その場合は、もう一度実行するとまとめて折りたためます。Microsoft Learn

次のショートカットもよく使われます。

Ctrl + M, Ctrl + O

これは「定義まで折りたたむ」操作で、クラス内のメソッドなどをまとめて折りたたします。ただし、#region自体を折りたたむかどうかは、Visual Studioのアウトライン設定によって異なることがあります。

3-4. #regionが折りたためないときの確認ポイント

#regionを記述しても折りたためない場合は、次の点を確認しましょう。

まず、#region#endregionが正しく対応しているか確認します。

C#
#region メソッド

public void Run()
{
}

// #endregionが抜けている

正しくは次のように記述します。

C#
#region メソッド

public void Run()
{
}

#endregion

次に、スペルが正しいか確認します。

C#
#regoin メソッド
#endregion

regionの文字順を間違えると認識されません。

正しくは次のとおりです。

C#
#region メソッド
#endregion

そのほか、次の項目も確認してください。

  • ファイルがC#ファイルとして認識されているか

  • 拡張子が.csになっているか

  • Visual Studioのアウトライン機能が停止されていないか

  • コード内に大きな構文エラーが発生していないか

  • #region#ifなどの範囲が不正に交差していないか

  • エディターやC#関連機能が正常に読み込まれているか

アウトライン機能を停止していた場合は、「編集」メニューの「アウトライン」から自動アウトラインを再開します。Visual Studioでは、Ctrl + M, Ctrl + Pによって文書全体のアウトライン情報を停止できるため、誤って実行していないかも確認しましょう。Microsoft Learn

4. C#で#regionを使うメリット

4-1. 長いソースコードを見やすく整理できる

#regionの大きなメリットは、長いソースコードを折りたたみ、画面上の情報量を減らせることです。

C#
#region 商品検索
// 複数の検索メソッド
#endregion

#region 商品登録
// 複数の登録メソッド
#endregion

#region 商品削除
// 複数の削除メソッド
#endregion

現在「商品登録」の処理だけを修正している場合は、それ以外のリージョンを折りたたむことで、作業対象に集中しやすくなります。

スクロール量が減るため、同じファイル内の離れた場所を行き来する回数も抑えられます。

4-2. 関連するメンバーをグループ化できる

複数のフィールド、プロパティ、メソッドを、役割ごとにまとめられます。

C#
#region 検証処理

private bool IsValidName(string name)
{
return !string.IsNullOrWhiteSpace(name);
}

private bool IsValidAge(int age)
{
return age >= 0;
}

#endregion

コードの位置だけでなく、リージョン名によっても各メンバーの役割を示せます。

特に、複数のインターフェースを実装しているクラスでは、インターフェース単位のグループ化が役立つ場合があります。

C#
#region IDisposable

public void Dispose()
{
}

#endregion

#region IComparable<User>

public int CompareTo(User? other)
{
return 0;
}

#endregion

4-3. 必要なコードに集中しやすくなる

大きなファイルを開くと、多数のメソッドやプロパティが一度に表示されます。#regionで作業対象外の部分を折りたためば、必要なコードだけを表示できます。

たとえば、画面の入力検証処理を修正するときは、データ保存や画面遷移のリージョンを折りたたんでおけます。

C#
#region 入力検証
// 現在修正している処理
#endregion

#region データ保存
// 折りたたむ
#endregion

#region 画面遷移
// 折りたたむ
#endregion

ただし、これは一時的に視認性を高める効果です。根本的にコード量が多すぎる場合は、クラスやメソッドの分割も検討しましょう。

4-4. 自動生成コードや定型コードを隠せる

自動生成されたコードや、普段は変更しない定型コードを折りたたむ用途にも#regionは適しています。

C#
#region 自動生成コード

public string GeneratedProperty1 { get; set; } = string.Empty;
public string GeneratedProperty2 { get; set; } = string.Empty;
public string GeneratedProperty3 { get; set; } = string.Empty;

#endregion

大量の定型コードが必要でも、開発者が頻繁に確認する必要がない場合は、リージョンで隠すことで主要な処理を見つけやすくなります。

ただし、自動生成コードを手書きコードと同じファイルに置く必要がない場合は、別ファイルやpartialクラスに分割する方法も有効です。

4-5. チーム内でコードの区切りを共有できる

リージョン名を統一すると、チーム内でソースコードの区切りを共有できます。

たとえば、次のようなルールを決められます。

C#
#region Public Methods
#endregion

#region Private Methods
#endregion

#region Event Handlers
#endregion

または、日本語で統一することもできます。

C#
#region 公開メソッド
#endregion

#region 非公開メソッド
#endregion

#region イベント処理
#endregion

メンバーの並び順とリージョン名が統一されていれば、初めて開くファイルでも目的の処理を探しやすくなります。

一方で、メンバーを追加するたびに適切なリージョンへ移動させる必要があります。運用ルールが守られないと、リージョン名と内容が一致しなくなる点には注意が必要です。

5. #regionを使わない方がいいと言われる理由

5-1. 長すぎるクラスやメソッドを隠してしまう

#regionを使うと、大量のコードを画面上から隠せます。しかし、コードが短くなったわけではありません。

たとえば、1,000行あるクラスを10個のリージョンに分けると、折りたたんだ状態では整っているように見えます。

C#
#region ユーザー処理
#endregion

#region 注文処理
#endregion

#region 商品処理
#endregion

#region メール処理
#endregion

しかし、1つのクラスがユーザー、注文、商品、メールという複数の機能を担当しているなら、クラスの責務が大きすぎる可能性があります。

リージョンで隠すのではなく、次のようにクラスを分割した方が構造を理解しやすくなります。

UserService.cs
OrderService.cs
ProductService.cs
MailService.cs

#regionはコード量を減らす機能ではないため、肥大化したクラスへの根本的な対策にはなりません。

5-2. コードの責務が多いことに気づきにくくなる

1つのクラスに多くのリージョンがある場合、そのクラスが多数の責務を抱えている可能性があります。

C#
#region データベース接続
#endregion

#region 入力検証
#endregion

#region PDF出力
#endregion

#region メール送信
#endregion

折りたたんでいると整然として見えますが、実際にはデータベース接続、検証、PDF出力、メール送信という異なる処理が同じクラスに集まっています。

このような場合は、役割ごとにクラスを分ける方法を検討します。

DatabaseRepository
InputValidator
PdfExporter
MailSender

リージョンの数が増えたときは、「整理できた」と考えるだけでなく、「クラスを分割するべきではないか」と見直すことが重要です。

5-3. 折りたたまないと全体像を把握しづらい

リージョンを多用したコードでは、初期状態で多くの部分が折りたたまれていることがあります。

C#
#region 初期化
#endregion

#region 読み込み
#endregion

#region 更新
#endregion

#region 削除
#endregion

リージョン名だけでは、内部でどのメソッドが定義されているか分かりません。全体像を確認するには、リージョンを一つずつ展開する必要があります。

また、あるメソッドから別のメソッドが呼び出されている場合、呼び出し先が折りたたまれていると処理の流れを追いにくくなることがあります。

コード自体が適切な長さで、クラスの責務が明確であれば、折りたたまなくても全体像を把握しやすくなります。

5-4. リージョン名と実際の処理がずれることがある

開発中にメソッドを追加・変更していると、リージョン名と中身が一致しなくなる場合があります。

C#
#region 検索処理

public User? FindUser(int id)
{
return null;
}

public void DeleteUser(int id)
{
// 削除処理
}

#endregion

「検索処理」というリージョン内に削除処理が入っており、分類が正しくありません。

このようなずれが増えると、リージョン名を手がかりにコードを探せなくなります。メソッドを追加したときに分類を更新する運用が必要です。

ただし、分類を維持するための作業が頻繁に必要なら、リージョンではなくクラス自体の構成を見直した方がよい可能性があります。

5-5. 入れ子が増えるとコード構造が複雑になる

リージョンを何段にも入れ子にすると、開始位置と終了位置の対応が分かりにくくなります。

C#
#region データ処理

#region ユーザー

#region 検索

public void SearchUser()
{
}

#endregion

#endregion

#endregion

このような構造では、リージョンの階層を確認するだけでも負担になります。

また、実際のC#コードにはクラス、メソッド、ifforなどの階層があります。そこへリージョンの階層が加わると、視覚的な構造が複雑になります。

入れ子が必要になった場合は、外側の分類単位を別クラスや別ファイルに分けられないか検討しましょう。

5-6. 開発環境によって表示や操作性が異なる

#regionはC#のディレクティブですが、折りたたみ方やショートカット、初期表示などは使用するエディターによって異なる場合があります。

Visual Studioでは標準のアウトライン機能として操作できますが、Visual Studio CodeやJetBrains Riderなどでは、表示方法やショートカットが異なることがあります。

チームメンバーが別々の開発環境を使っている場合、次のような差が生じる可能性があります。

  • 折りたたみ状態の扱いが異なる

  • ショートカットキーが異なる

  • リージョン名の表示方法が異なる

  • 一括操作の方法が異なる

  • 設定や拡張機能によって動作が変わる

そのため、#regionを前提にしなければ理解できないコード構成は避けるのが安全です。

5-7. コードレビューや差分確認の妨げになる場合がある

コードレビューでは、変更した処理だけでなく、その前後や関連メソッドも確認します。

リージョンが折りたたまれていると、レビュー対象の周辺コードを見落とす可能性があります。また、レビューのたびにリージョンを展開する操作が必要になる場合もあります。

リージョン名の追加や変更もソースコード上の差分として記録されます。

Diff
- #region 処理
+ #region 注文登録処理

適切な名称変更であれば問題ありませんが、リージョンの整理だけを目的とした変更が大量に含まれると、本来確認したいロジックの差分が埋もれることがあります。

リージョンの追加、削除、並べ替えと、機能修正を同時に行う場合は、レビューしやすい変更単位になっているか注意しましょう。

6. #regionを使ってもよいケース

#regionは必ず避けるべき機能ではありません。目的が明確で、コード設計上の問題を隠すためでなければ、有効に使える場合があります。

代表的なのは、自動生成コードや定型コードをまとめるケースです。

C#
#region 自動生成されたプロパティ

public string Column1 { get; set; } = string.Empty;
public string Column2 { get; set; } = string.Empty;
public string Column3 { get; set; } = string.Empty;

#endregion

多数のインターフェースを実装しており、実装単位を明確にしたい場合にも利用できます。

C#
public class ResourceManager :
IDisposable,
IAsyncDisposable
{
#region IDisposable

public void Dispose()
{
// 同期的な解放処理
}

#endregion

#region IAsyncDisposable

public ValueTask DisposeAsync()
{
// 非同期の解放処理
return ValueTask.CompletedTask;
}

#endregion
}

部分クラスの中で、ツールによって生成されたコードと手作業のコードを区別したい場合にも役立ちます。

C#
#region Designer generated code

private void InitializeComponent()
{
// 初期化処理
}

#endregion

また、学習用のサンプルコードで、説明対象を章ごとに分ける目的にも使えます。

C#
#region 例1:変数
#endregion

#region 例2:条件分岐
#endregion

#region 例3:繰り返し
#endregion

#regionを使うか迷った場合は、次の観点で判断しましょう。

  • リージョンの中身は同じ役割で統一されているか

  • コードの肥大化を隠すために使っていないか

  • クラスやファイルを分割した方が分かりやすくならないか

  • 折りたたまなくてもコードを理解できるか

  • リージョン名と内容を継続的に一致させられるか

  • チームのコーディングルールに合っているか

最初にクラスやメソッドの適切な分割を検討し、それでも同じファイル内で整理する意味がある場合に#regionを使うとよいでしょう。

まとめ

C#の#regionは、#endregionまでのコードをVisual Studioなどのエディター上で折りたたむためのプリプロセッサディレクティブです。

基本構文は次のとおりです。

C#
#region リージョン名

// 折りたたむコード

#endregion

#regionはコードの表示を整理する機能であり、プログラムの実行結果には影響しません。長いソースコードを見やすくしたり、関連するメンバーをまとめたり、自動生成コードを隠したりする用途に役立ちます。

一方で、多用すると長すぎるクラスや責務の多さを隠してしまいます。リージョンの入れ子、内容と名前のずれ、コードレビューのしにくさにも注意が必要です。

#regionを使いたくなったときは、まずクラスやメソッドを適切に分割できないか検討しましょう。そのうえで、自動生成コードやインターフェース実装など、明確な目的がある範囲に限定して使うことが大切です。