アクセス修飾子を理解しよう!

[C#] アクセス修飾子を理解しよう!

※ 当サイトは広告を含みます。

ここではC#のアクセス修飾子について学びます。これもクラスの延長線の話になります。
最低でもクラスと継承の知識が必要なので、忘れてしまった人は以下で復習しましょう。

アクセス修飾子(Access Modifiers)

アクセス修飾子とは、クラス、メソッド、プロパティ、フィールド等へのアクセス範囲を制限するために使います。

既に解説したprivatepublicを含めると、全部で5種類(public, protected, internal, private, file)あります。
さらに複数のアクセス修飾子の組み合わせが可能で、実際には7つのアクセスレベルを指定できます。

アクセス修飾子

以下は構文の例です。

アクセス修飾子

public

最もアクセス制限が緩いです。と言うか、アクセス制限がされません。
つまり、publicを記述すると外部からのアクセスが無条件で許可されます。


namespace Sample
{
  public class Base
  {
    // publicフィールド
    public int value = 100;
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      var b = new Base();

      // 無条件にアクセスが可能
      System.Console.WriteLine(b.value);
      b.value *= 2;
      System.Console.WriteLine(b.value);
    }
  }
}

publicはアクセス制限がないので、基本的に外部からクラスを操作するためのメソッドやプロパティにしか付けません。
特にフィールドに付けることはなく、仮に指定が必要になってる場合は設計の問題を疑ったほうがいいです。

管理人
管理人

さっきのサンプルコードは非常に悪い例です。こうすると外部から勝手に値を変更できるのでバグの元になります。

protected

後に説明するprivateより少し緩い版です。指定するとクラス自身か継承したクラスしかアクセスできません。
ちょっと例が難しいのですが、外部公開までは必要ないけど、自分を継承したクラスはアクセス可能にしたい場合に使います。


namespace Sample
{
  public class Base
  {
    // protectedフィールド
    protected int value = 100;
  }

  public class Derived : Base
  {
    public int GetValue()
    {
      // 継承したクラスはアクセス可能
      return value;
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      var d = new Derived();

      System.Console.WriteLine(d.GetValue());

      // 外部はアクセス不可能
      //System.Console.WriteLine(d.value);
    }
  }
}
管理人
管理人

クラスを継承しない限りはprivateと同義です。

internal

アクセスを同一アセンブリに限定します。この時点では分かりづらいと思いますが、同一アセンブリとは同じプロジェクトを意味します。
以前にプログラムはプロジェクト単位でも分割できると話しましたが、その時に別プロジェクトからのアクセスが禁止になります。


namespace Sample
{
  // 別プロジェクトからはアクセス不可能
  internal class InternalClass
  {
  }

  // 別プロジェクトでもアクセス可能
  public class PublicClass
  {
  }
}
管理人
管理人

同プロジェクトから見ればpublicを指定するのと同義です。

private

アクセスを自分自身に限定します。後述するfileが特殊なため、これが実質的に最も厳しいアクセス制限となります。
基本的な考え方として、クラス内のフィールドは全てprivateにします。それ以外だと内部でしか利用しないメソッドやプロパティに付けます。

protectedとの違いは継承先からのアクセス制限です。privateは継承先も含め、自身以外はアクセス禁止になります。


namespace Sample
{
  public class Base
  {
    // privateフィールド
    private int v1 = 100;

    // protectedフィールド
    protected int v2 = 300;
  }

  public class Derived : Base
  {
    public void Display()
    {
      // アクセス不可能
      //System.Console.WriteLine(v1);

      // アクセス可能
      System.Console.WriteLine(v2);
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      var d = new Derived();
      d.Display();
    }
  }
}

file

これはアクセスを現在のソースコードに限定します。つまり別のファイルからのアクセスを禁止します。
別ファイルでも同名の名前空間の内部は同じスコープになるため、そこで名前が被るような場合にfileを使うことで被りが許容されます。


namespace Sample
{
  // ファイル内からのみアクセス可能
  file class Base
  {
    public void Display()
    {
      System.Console.WriteLine("りさ");
    }
  }

  internal class Program
  {
    static void Main(string[] args)
    {
      var b = new Base();
      b.Display();
    }
  }
}

これまで当然のように書いてますが、本来は1ファイルに1クラスが原則です。例のように1つのファイルに全てを記述するパターンは少ないです。
それでも1ファイルに複数のクラス、例えば補佐するサブクラス等を書きたい場合があり、そういうパターンで利用すると便利だったりします。

管理人
管理人

そもそも上位の名前空間で名前被りは設計的にどうなのって意見もあるので賛否両論。

アクセス修飾子の組み合わせ

先程のアクセス修飾子を組み合わせて使えるパターンです。と言っても無理に覚える必要はありません。
正直、先程のfileを除く4つ(public, protected, internal, private)があれば基本的に困りません。

管理人
管理人

知識勢でも目指さない限りは単体4個で十分です。

protected internal

これはprotectedまたはinternalです。通常のprotectedに加えて別アセンブリからもアクセスできます。
ただ、正直なところ僕はこれの使い道が分かりません。と言うのもinternalが付くと同一アセンブリで全許可になります。

管理人
管理人

要はアクセス範囲が広すぎると思うんですよね。仮に同一アセンブリを1人で開発した場合でも全許可は雑。

private protected

パターンが無いからこの組み合わせを採用したんでしょうね。ただただ分かりづらくなってます。
これは実質的にprotectedかつinternalです。つまり、さっきの話のアクセス範囲が広すぎ問題を解決してくれます。

管理人
管理人

いっそprotected internalの機能を作り替えたほう幸せだったのでは。

記述可能な項目

先程のアクセス修飾子ですが、何でもかんでも記述できる訳ではありません。
大雑把に分類すると、記述対象がトップレベルか否かで記述可能なアクセス修飾子が変わります。

トップレベルの場合

これはnamespace配下に記述したクラス宣言など、つまりは最上位に位置する場合を意味します。
この場合に記述できるのはinternalpublicの2種類のみです。ちなみにDefault値はinternalになります。

あまり難しく考えないで欲しいのですが、これは当たり前のことで、最上位のクラスに他のアクセス修飾子を付けると誰もアクセスできません。
つまりは同じアセンブリだろうと、誰もアクセスできないゴミみたいなクラスが誕生します。これでは意味がないですよね。


namespace Sample
{
  // 誰もアクセスできないからビルドエラー
  private class Base
  {
  }
}

メンバの場合

トップレベルでない場合、つまりは何らかのメンバになってる場合です。
例えばクラスに含まれるフィールドやメソッド、クラスのクラスとかもメンバって言います。

この場合は先程説明した数々のアクセス修飾子を記述できます。なお、Default値は大体privateになります(たぶん)。

りさ
りさ

曖昧ですね。

管理人
管理人

個人的にはアクセス修飾子は省略せず記述したほうが良いです。と言うか、僕自身が省略しないのでDefault値を知りません。

あとがき

最初はpublic, protected, privateの3つを覚えれば十分だと思う。正直、internalも人それぞれな印象。
少なくとも何でもかんでもpublicを指定するのは辞めましょう。インテリセンス利用時の見栄えも悪くなります。

◆ C#に関する学習コンテンツ

この記事は参考になりましたか?

関連記事

コメント

この記事へのコメントはありません。