bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] Access Modifiers(アクセス修飾子)を整理する — public から file まで全 7 種のスコープと使い分け

[C#] Access Modifiers(アクセス修飾子)を整理する — public から file まで全 7 種のスコープと使い分け

Apr 19, 2026 C# , .NET bucket-sort

C# のアクセス修飾子(Access Modifiers)は、型やメンバーの可視性を制御するキーワードです。適切に設定することで、外部に公開する必要のない実装の詳細を隠蔽(カプセル化)し、保守性と安全性を高められます。

C# 11 で追加された file を含め、現在は 7 種類のアクセス修飾子があります。

可視性の一覧

アクセス修飾子 同じクラス 派生クラス(同一アセンブリ) 同一アセンブリ 派生クラス(別アセンブリ) 別アセンブリ
public ✅ ✅ ✅ ✅ ✅
private ✅ ❌ ❌ ❌ ❌
protected ✅ ✅ ❌ ✅ ❌
internal ✅ ✅ ✅ ❌ ❌
protected internal ✅ ✅ ✅ ✅ ❌
private protected ✅ ✅ ❌ ❌ ❌
file 同一ファイル内のみ ❌ ❌ ❌ ❌

protected internal は「protected OR internal」、private protected は「protected AND internal」と覚えると分かりやすいです。

public — どこからでもアクセス可能

最も開放的な修飾子です。型やメンバーをライブラリの利用者・別プロジェクトに公開する場合に使います。

public class Greeter
{
    public string Message { get; set; } = "Hello!";

    public void Greet()
    {
        Console.WriteLine(Message);
    }
}

// どこからでもアクセスできる
var g = new Greeter();
g.Greet(); // Hello!

public の適用対象

  • クラス・構造体・インターフェース・列挙型(トップレベル型)
  • メソッド・プロパティ・フィールド・イベント・コンストラクタ
  • ネストされた型

private — 同じクラス内のみ

最も制限的な修飾子です。クラスの内部実装を隠すために使います。クラスメンバーのデフォルトのアクセス修飾子です。

public class BankAccount
{
    private decimal _balance; // 外部からアクセス不可

    public BankAccount(decimal initial)
    {
        _balance = initial;
    }

    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Amount must be positive.");
        _balance += amount;
    }

    public decimal GetBalance() => _balance;
}

var account = new BankAccount(1000m);
account.Deposit(500m);
Console.WriteLine(account.GetBalance()); // 1500

// account._balance = 9999; // コンパイルエラー:private メンバーにはアクセスできない

ネストされた型からはアクセスできる

private メンバーは同じクラス内のネストされた型(inner class)からもアクセスできます。

public class Outer
{
    private int _secret = 42;

    public class Inner
    {
        public void Reveal(Outer outer)
        {
            // ネストされた型から外側クラスの private メンバーにアクセスできる
            Console.WriteLine(outer._secret); // 42
        }
    }
}

var outer = new Outer();
var inner = new Outer.Inner();
inner.Reveal(outer); // 42

protected — 同じクラスと派生クラスのみ

継承関係にあるクラスに実装の詳細を共有したい場合に使います。アセンブリの内外を問わず、派生クラスからアクセスできます。

public class Shape
{
    protected double _area;

    protected void LogArea()
    {
        Console.WriteLine($"Area = {_area}");
    }
}

public class Circle : Shape
{
    public Circle(double radius)
    {
        // 派生クラスから protected メンバーにアクセスできる
        _area = Math.PI * radius * radius;
    }

    public void PrintArea() => LogArea();
}

var c = new Circle(5);
c.PrintArea(); // Area = 78.53981633974483

// c._area = 0;    // コンパイルエラー:外部からはアクセスできない
// c.LogArea();     // コンパイルエラー:外部からはアクセスできない

protected メンバーへの制約

protected メンバーには「自分自身のインスタンス経由」でしかアクセスできないという制約があります。

public class Circle : Shape
{
    public void Compare(Shape other)
    {
        Console.WriteLine(_area);       // OK:自分自身の protected メンバー
        // Console.WriteLine(other._area); // コンパイルエラー:別インスタンスの protected には直接アクセスできない
    }
}

internal — 同じアセンブリ内のみ

internal はアセンブリ(= プロジェクト)を境界とするアクセス制御です。同じプロジェクト内であればどこからでもアクセスでき、別プロジェクトからはアクセスできません。トップレベル型のデフォルトのアクセス修飾子です。

// ── MyLibrary プロジェクト ──

internal class InternalHelper
{
    internal void DoWork()
    {
        Console.WriteLine("Internal work");
    }
}

public class PublicService
{
    public void Execute()
    {
        // 同じアセンブリ内なのでアクセスできる
        var helper = new InternalHelper();
        helper.DoWork();
    }
}
// ── ConsoleApp プロジェクト(別アセンブリ)──

var service = new PublicService();
service.Execute(); // OK

// var helper = new InternalHelper(); // コンパイルエラー:別アセンブリからはアクセスできない

InternalsVisibleTo — テストプロジェクトへの公開

internal メンバーをユニットテスト用の別プロジェクトからアクセスしたい場合は、InternalsVisibleTo 属性を使います。

// MyLibrary/AssemblyInfo.cs
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("MyLibrary.Tests")]

これにより MyLibrary.Tests プロジェクトからは internal メンバーにアクセスできるようになります。

protected internal — protected OR internal

protected internal は「同じアセンブリ内からアクセスできる」または「派生クラスからアクセスできる」の和集合です。

// ── MyLibrary プロジェクト ──

public class BaseComponent
{
    protected internal void Initialize()
    {
        Console.WriteLine("Initialized");
    }
}

public class SameAssemblyUser
{
    public void Setup()
    {
        var component = new BaseComponent();
        component.Initialize(); // OK:同じアセンブリなので internal としてアクセスできる
    }
}
// ── PluginProject プロジェクト(別アセンブリ)──

public class CustomComponent : BaseComponent
{
    public void Start()
    {
        Initialize(); // OK:派生クラスなので protected としてアクセスできる
    }
}

public class ExternalUser
{
    public void Setup()
    {
        var component = new BaseComponent();
        // component.Initialize(); // コンパイルエラー:別アセンブリかつ派生でもないのでアクセスできない
    }
}

フレームワーク内部では自由にアクセスさせつつ、継承を通じて外部の拡張にも開放する、というパターンに向いています。

private protected — protected AND internal

C# 7.2 で導入された private protected は、「同じアセンブリ内」かつ「派生クラス」の積集合でのみアクセスできます。

// ── MyLibrary プロジェクト ──

public class BaseEngine
{
    private protected void CoreProcess()
    {
        Console.WriteLine("Core processing");
    }
}

// 同じアセンブリ内の派生クラス → OK
public class InternalEngine : BaseEngine
{
    public void Run()
    {
        CoreProcess(); // OK:同じアセンブリ内の派生クラス
    }
}

// 同じアセンブリ内だが派生クラスではない → NG
public class SameAssemblyUser
{
    public void Try()
    {
        var engine = new BaseEngine();
        // engine.CoreProcess(); // コンパイルエラー:派生クラスではない
    }
}
// ── PluginProject プロジェクト(別アセンブリ)──

public class ExternalEngine : BaseEngine
{
    public void Run()
    {
        // CoreProcess(); // コンパイルエラー:派生クラスだが別アセンブリ
    }
}

ライブラリ内部でだけ継承を許可し、外部からの継承では触れさせたくないメンバーを保護するのに有効です。

file — 同一ファイル内のみ(C# 11)

C# 11(.NET 7)で導入された file 修飾子は、型宣言(class・struct・interface・enum・delegate)に付けられるアクセス修飾子で、同じソースファイル内からのみアクセス可能にします。

// Validators.cs

file class EmailValidator
{
    public bool IsValid(string email) => email.Contains('@');
}

public class UserService
{
    private readonly EmailValidator _validator = new();

    public bool ValidateEmail(string email) => _validator.IsValid(email);
}
// OtherFile.cs

// var v = new EmailValidator(); // コンパイルエラー:別ファイルからはアクセスできない

file の主な用途

file はソースジェネレーターとの相性を意識して設計されましたが、手書きのコードでも以下の場面で役立ちます。

  • ファイルスコープのヘルパークラス — そのファイル内でしか使わないユーティリティをファイルに閉じ込める
  • 名前の衝突回避 — 同名の型が別ファイルに存在してもコンパイルエラーにならない
// FileA.cs
file class Helper
{
    public static string Tag => "A";
}

// FileB.cs
file class Helper  // 同名でも衝突しない
{
    public static string Tag => "B";
}

file の制約

  • file はメンバー(メソッド・プロパティなど)には付けられない。型宣言のみ
  • file 型をネストされた型にはできない。トップレベル型のみ
  • public なメンバーの戻り値やパラメーターに file 型を使うとコンパイルエラーになる

デフォルトのアクセス修飾子

明示的にアクセス修飾子を書かなかった場合のデフォルトは以下のとおりです。

対象 デフォルト
トップレベルの型(class・struct・interface・enum) internal
クラスのメンバー(メソッド・プロパティ・フィールドなど) private
インターフェースのメンバー public
構造体のメンバー private
enum のメンバー public
ネストされた型 private
// デフォルトは internal
class DefaultClass
{
    // デフォルトは private
    int _value;

    // デフォルトは private
    void DoSomething() { }
}

意図を明確にするために、private であっても明示的に書くチームも多くあります。

protected internal と private protected の比較

この 2 つは混同しやすいため、改めて対比します。

protected internal  = protected OR  internal  →  広い(和集合)
private protected   = protected AND internal  →  狭い(積集合)
シナリオ protected internal private protected
同じアセンブリ・派生クラス ✅ ✅
同じアセンブリ・非派生クラス ✅ ❌
別アセンブリ・派生クラス ✅ ❌
別アセンブリ・非派生クラス ❌ ❌

まとめ

アクセス修飾子 導入バージョン 一言で
public C# 1.0 どこからでもアクセス可能
private C# 1.0 同じ型の内部のみ
protected C# 1.0 同じ型 + 派生クラス
internal C# 1.0 同じアセンブリ内のみ
protected internal C# 1.0 protected OR internal
private protected C# 7.2 protected AND internal
file C# 11 同一ソースファイル内のみ

アクセス修飾子は「公開する必要がないものは隠す」を原則に選択します。まず private から始めて、必要に応じて段階的に緩めていくのが安全なアプローチです。

C# .NET アクセス修飾子 カプセル化
← [C#] class のコンストラクタを深掘りする — 基本・チェーン・Expression-Bodied・out 変数・Primary Constructor [C#] プロパティ(Properties)を整理する — 基本構文から自動実装・計算プロパティまで →

Related Posts

  • [C#] 入れ子クラス(Nested Class) — クラスの中にクラスを定義する設計テクニック Apr 27, 2026
  • [C#] プロパティ(Properties)を整理する — 基本構文から自動実装・計算プロパティまで Apr 20, 2026
  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026
  • [C#] Disposable Objects — IDisposable / Dispose() と using 構文 May 12, 2026

Table of Contents

  • 可視性の一覧
  • public — どこからでもアクセス可能
    • public の適用対象
  • private — 同じクラス内のみ
    • ネストされた型からはアクセスできる
  • protected — 同じクラスと派生クラスのみ
    • protected メンバーへの制約
  • internal — 同じアセンブリ内のみ
    • InternalsVisibleTo — テストプロジェクトへの公開
  • protected internal — protected OR internal
  • private protected — protected AND internal
  • file — 同一ファイル内のみ(C# 11)
    • file の主な用途
    • file の制約
  • デフォルトのアクセス修飾子
  • protected internal と private protected の比較
  • まとめ

Recent Posts

  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026
  • [C#] Disposable Objects — IDisposable / Dispose() と using 構文 May 12, 2026
  • [C#] Finalizable Objects — Finalize() の役割と使いどころ May 11, 2026
  • [C#] System.GC クラスを整理する — ガベージコレクションを制御するための API May 10, 2026
  • [C#] IComparable と IComparer — オブジェクトの順序比較と複数ソート戦略 May 9, 2026

Categories

  • C#63
  • .NET62
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • Apache
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • パフォーマンス
  • DoS
  • Nginx
  • Windows
  • WordPress
  • メモリ管理
  • 監視
  • 設計
  • Amazon Linux 2023
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • OPCache
  • Webサーバー
  • オブジェクト指向
  • クラス設計
  • コレクション
  • デザインパターン
  • パターンマッチング
  • 継承
  • 認可
  • Aurora
  • Blade
  • Grafana
  • Hugo
  • InfluxDB
  • Policy
  • Record
  • SSG
  • インターフェース
  • エラーハンドリング
  • カプセル化
  • ガベージコレクション
  • モニタリング
  • 例外
Powered by Hugo & Explore Theme.