C#のアクセス修飾子とは?6種類の使い分けを実例で分かりやすく解説

C#

C#でプログラミングをしていると、publicprivateといったキーワードを目にすることがありますよね。これらは「アクセス修飾子」と呼ばれるもので、クラスやメソッド、プロパティなどへのアクセス範囲を制御する重要な役割を担っています。

今回は、C#のアクセス修飾子について、それぞれの特徴と使い分け方を実例を交えて分かりやすく解説していきます。

スポンサーリンク

アクセス修飾子って何?

アクセス修飾子は、クラスやメソッド、プロパティ、フィールドなどに対して「どこからアクセスできるか」を指定するためのキーワードです。

たとえて言うなら、家の中にある部屋のようなものです。

  • リビング(public)→誰でも入れる
  • 寝室(private)→自分だけ入れる
  • 子供部屋(protected)→家族なら入れる
  • 倉庫(internal)→同じ家に住んでいる人なら入れる

このように、アクセス修飾子を使い分けることで、コードの安全性を高め、意図しない使い方を防ぐことができます。

なぜアクセス修飾子が必要なの?

アクセス修飾子を適切に使うことで、以下のようなメリットがあります。

カプセル化の実現

クラスの内部データを隠蔽し、外部から直接操作されないようにできます。これにより、データの整合性を保ちやすくなります。

バグの防止

重要なデータやメソッドを保護することで、意図しない場所から変更されるリスクを減らせます。

保守性の向上

コードの影響範囲を限定できるので、修正や変更がしやすくなります。

設計意図の明示

どのメンバーを外部に公開したいのか、コードを見ただけで分かるようになります。

C#のアクセス修飾子6種類

C#には、基本的に6種類のアクセス修飾子があります。それぞれ見ていきましょう。

1. public(パブリック)

publicは最も制限の緩いアクセス修飾子です。

アクセス可能な範囲

  • どこからでもアクセスできます
  • 同じクラス内はもちろん、他のクラスや他のアセンブリ(プロジェクト)からもアクセス可能です

使用例

public class Car
{
    public string Model = "Mustang";

    public void StartEngine()
    {
        Console.WriteLine("エンジンを始動します");
    }
}

class Program
{
    static void Main()
    {
        Car myCar = new Car();
        Console.WriteLine(myCar.Model);  // アクセスできる
        myCar.StartEngine();  // 呼び出せる
    }
}

いつ使う?

外部から自由に使ってほしいメソッドやプロパティに使います。ただし、安易にpublicにすると後々の変更が困難になるので注意が必要です。

2. private(プライベート)

privateは最も制限の厳しいアクセス修飾子です。

アクセス可能な範囲

  • 同じクラスまたは構造体の中からのみアクセスできます
  • 他のクラスからは一切アクセスできません

使用例

public class BankAccount
{
    private decimal balance = 0;  // 残高は外部から直接変更できない

    public void Deposit(decimal amount)
    {
        if (amount > 0)
        {
            balance += amount;  // クラス内からはアクセスできる
        }
    }

    public decimal GetBalance()
    {
        return balance;
    }
}

class Program
{
    static void Main()
    {
        BankAccount account = new BankAccount();
        // account.balance = 1000000;  // エラー!privateなのでアクセスできない
        account.Deposit(1000);  // これはOK
        Console.WriteLine(account.GetBalance());
    }
}

いつ使う?

クラスの内部処理で使うデータやメソッドに使います。外部に公開する必要のないものは、基本的にprivateにするのがベストプラクティスです。

重要な注意点

アクセス修飾子を指定しない場合、クラスや構造体のメンバーはデフォルトでprivateになります。これを知らないとエラーの原因になるので覚えておきましょう。

3. protected(プロテクテッド)

protectedは、継承関係にあるクラスからのアクセスを許可する修飾子です。

アクセス可能な範囲

  • 同じクラス内からアクセスできます
  • そのクラスを継承した派生クラスからアクセスできます
  • 他のクラスからは直接アクセスできません

使用例

public class Vehicle
{
    protected string engineType = "ガソリン";

    protected void StartEngine()
    {
        Console.WriteLine($"{engineType}エンジンを始動");
    }
}

public class Car : Vehicle
{
    public void Drive()
    {
        StartEngine();  // 継承しているのでアクセスできる
        Console.WriteLine($"エンジンタイプ: {engineType}");
    }
}

class Program
{
    static void Main()
    {
        Car myCar = new Car();
        myCar.Drive();  // これはOK
        // myCar.StartEngine();  // エラー!protectedなので外部からは呼び出せない
    }
}

いつ使う?

親クラスの機能を子クラスに共有したいけれど、外部には公開したくない場合に使います。

4. internal(インターナル)

internalは、C#独自のアクセス修飾子です。

アクセス可能な範囲

  • 同じアセンブリ(プロジェクト)内であればどこからでもアクセスできます
  • 他のアセンブリからはアクセスできません

使用例

internal class DatabaseHelper
{
    internal void Connect()
    {
        Console.WriteLine("データベースに接続しました");
    }
}

class Program
{
    static void Main()
    {
        DatabaseHelper helper = new DatabaseHelper();
        helper.Connect();  // 同じアセンブリ内なのでOK
    }
}

いつ使う?

同じプロジェクト内では自由に使いたいけれど、DLLとして外部に公開するときには隠したい機能に使います。

重要な知識

名前空間で直接宣言されたクラスは、アクセス修飾子を指定しない場合、デフォルトでinternalになります。

5. protected internal(プロテクテッド インターナル)

protectedinternalを組み合わせた修飾子です。

アクセス可能な範囲

  • 同じアセンブリ内のどのクラスからでもアクセスできます
  • 他のアセンブリでも、継承した派生クラスからはアクセスできます

つまり、「protectedまたはinternalのどちらか」という意味になります。

使用例

public class BaseClass
{
    protected internal void ShowMessage()
    {
        Console.WriteLine("protected internalメソッド");
    }
}

class AnotherClass
{
    public void Test()
    {
        BaseClass obj = new BaseClass();
        obj.ShowMessage();  // 同じアセンブリ内なのでアクセスできる
    }
}

いつ使う?

同じプロジェクト内では自由に使えて、さらに他のプロジェクトでも継承した場合には使えるようにしたいときに使います。

6. private protected(プライベート プロテクテッド)

C# 7.2以降で追加された、最も制限的な組み合わせです。

アクセス可能な範囲

  • 同じアセンブリ内で、かつ継承した派生クラスからのみアクセスできます

つまり、「protectedかつinternal」という意味になります。

使用例

public class Parent
{
    private protected int value = 100;

    public void SetValue(int v)
    {
        value = v;
    }
}

class Child : Parent
{
    public void ShowValue()
    {
        Console.WriteLine($"値: {value}");  // 同じアセンブリの派生クラスなのでOK
    }
}

class Program
{
    static void Main()
    {
        Parent obj = new Parent();
        // obj.value = 50;  // エラー!アクセスできない

        Child child = new Child();
        child.ShowValue();  // これはOK
    }
}

いつ使う?

同じプロジェクト内での継承は許可したいけれど、それ以外のアクセスは一切禁止したい場合に使います。

アクセス修飾子の比較表

分かりやすく表にまとめると、以下のようになります。

アクセス修飾子同じクラス派生クラス(同じアセンブリ)派生クラス(他のアセンブリ)同じアセンブリの他のクラス他のアセンブリの他のクラス
public
private××××
protected××
internal××
protected internal×
private protected×××

実践的な使い分けのコツ

アクセス修飾子を適切に選ぶためのポイントをまとめます。

原則1:最小限のアクセス権限から始める

迷ったら、まずprivateから始めましょう。

必要に応じて徐々にアクセス範囲を広げていくのが安全です。最初からpublicにしてしまうと、後で変更するのが難しくなります。

原則2:publicの使用は慎重に

publicにしたメンバーは、どこからでもアクセスできるため、後で仕様を変更すると広範囲に影響が出ます。

DLLとして外部に提供する場合は特に注意が必要です。本当に外部に公開する必要があるものだけをpublicにしましょう。

原則3:internalを積極的に活用する

同じプロジェクト内でのみ使う機能は、internalにするのがおすすめです。

publicより制限が厳しいため、修正時の影響範囲を把握しやすくなります。Visual Studioなどの開発環境では、「参照されている箇所」を簡単に確認できるので、安全に変更できます。

原則4:継承を考慮する

将来的にクラスを継承する可能性がある場合は、protectedを使って派生クラスに機能を共有できるようにしておきます。

ただし、継承を全く想定していないクラスであれば、privateのままで問題ありません。

原則5:構造体ではprotectedは使えない

構造体(struct)は継承をサポートしていないため、protectedprotected internalprivate protectedは使用できません。

よくあるエラーと対処法

エラー:’○○’ is inaccessible due to its protection level

このエラーは、アクセス権限のないメンバーにアクセスしようとしたときに発生します。

原因

  • privateなメンバーをクラスの外から参照しようとした
  • protectedなメンバーを継承関係のないクラスから参照しようとした

対処法

アクセス修飾子を確認し、適切な範囲からアクセスしているか確認してください。もし外部からアクセスする必要があるなら、アクセス修飾子を変更します。

アクセス修飾子を省略したらprivateになった

クラスや構造体のメンバーでアクセス修飾子を指定しないと、デフォルトでprivateになります。

class MyClass
{
    int number;  // privateになる
}

これは初心者がよく間違える点です。意図的にpublicにしたい場合は、必ず明示的に指定しましょう。

クラス自体のアクセス修飾子を忘れた

名前空間に直接宣言されたクラスでアクセス修飾子を指定しないと、デフォルトでinternalになります。

class MyClass  // internalになる
{
    // ...
}

他のアセンブリから使いたい場合は、明示的にpublicを指定する必要があります。

カプセル化とアクセス修飾子

オブジェクト指向プログラミングの重要な概念である「カプセル化」は、アクセス修飾子によって実現されます。

カプセル化の基本

カプセル化とは、データ(フィールド)をprivateにして外部から直接アクセスできないようにし、publicなメソッドやプロパティを通じてのみ操作できるようにすることです。

public class Person
{
    private string name;  // privateなフィールド
    private int age;

    // publicなプロパティを通じてアクセス
    public string Name
    {
        get { return name; }
        set 
        { 
            if (!string.IsNullOrEmpty(value))
            {
                name = value;
            }
        }
    }

    public int Age
    {
        get { return age; }
        set 
        { 
            if (value >= 0 && value <= 150)
            {
                age = value;
            }
        }
    }
}

このように、プロパティを通じてアクセスすることで、値の妥当性をチェックできます。

プロパティのアクセス修飾子

プロパティのgetterとsetterに対して、個別にアクセス修飾子を指定することもできます。

public class Product
{
    public string Name { get; private set; }

    public Product(string name)
    {
        Name = name;
    }
}

この例では、Nameプロパティは外部から読み取りはできますが、書き込みはクラス内からのみ可能です。

まとめ

C#のアクセス修飾子は、コードの安全性と保守性を高めるための重要な仕組みです。

6種類のアクセス修飾子をおさらいすると、以下のようになります。

  • public:どこからでもアクセス可能
  • private:同じクラス内のみアクセス可能
  • protected:同じクラスと派生クラスからアクセス可能
  • internal:同じアセンブリ内からアクセス可能
  • protected internal:同じアセンブリ内または派生クラスからアクセス可能
  • private protected:同じアセンブリ内の派生クラスからのみアクセス可能

基本的には、最小限のアクセス権限から始めて、必要に応じて範囲を広げていくのがベストプラクティスです。

アクセス修飾子を適切に使い分けることで、バグを防ぎ、メンテナンスしやすいコードを書けるようになりますよ。

コメント

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