C#では、アクセス修飾子を使用してクラス、メソッド、プロパティ、フィールドなどのアクセスレベルを制御することができます。アクセス修飾子を適切に活用することで、コードの安全性と可読性が向上します。この記事では、C#で使用できる主要なアクセス修飾子とその利点について解説させていただきます。
アクセス修飾子の種類とアクセシビリティレベル
C#のアクセス修飾子には、以下の種類があります。
public
private
protected
internal
file
これらのアクセス修飾子を使用することで、クラス、メソッド、プロパティ、フィールドなどに次のアクセシビリティレベルを指定できます。
アクセシビリティの宣言 | アクセシビリティレベルの説明 |
---|---|
public | どこからでもアクセス可能 |
private | 定義されたクラス内部でのみアクセス可能 |
protected | 定義されたクラスとその派生クラスからアクセス可能 |
internal | 同一アセンブリ(※)内でのみアクセス可能 |
protected internal | 同じアセンブリ(※)内および派生クラスからアクセス可能 |
private protected | 定義されたクラス内、または同じアセンブリ内の派生クラスからアクセス可能 |
file | 同じファイル内でのみアクセス可能 (主に.NETのソースジェネレーターが作成した型に適用されるもの) |
呼び出し場所における各アクセシビリティレベルのアクセス可否の一覧は、次の通りになります。
呼び出し場所 | public | protected internal | protected | internal | private protected | private | file |
---|---|---|---|---|---|---|---|
ファイル内 | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ |
クラス内 | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ✖️ |
派生クラス (同じアセンブリ) | ⭕ | ⭕ | ⭕ | ⭕ | ⭕ | ✖️ | ✖️ |
非派生クラス (同じアセンブリ) | ⭕ | ⭕ | ✖️ | ⭕ | ✖️ | ✖️ | ✖️ |
派生クラス (異なるアセンブリ) | ⭕ | ⭕ | ⭕ | ✖️ | ✖️ | ✖️ | ✖️ |
非派生クラス (異なるアセンブリ) | ⭕ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ |
一覧表だけではわかりにくいので、C#での規定のアクセシビリティレベル、各アクセス修飾子の利点と具体的な使用例を順に解説していきます。(file
修飾子は.NETソースジェネレーターが作成した型に適用されるのが主のため、以降の説明からは省いています。)
C#での既定のアクセシビリティレベル
C#でアクセス修飾子を指定しない場合の既定のアクセシビリティと、それぞれの型などに指定できるアクセシビリティは次の通りになっています。
- 名前空間:アクセス修飾子でアクセシビリティレベルの指定はできません。既定でアクセス制限なし(
public
同等)になります。 - トップレベルの型(名前空間直下など他の型に対して入れ子にされていない型):指定できるのは
internal
とpublic
だけです。既定はinternal
になります。 - 他の型の入れ子にされた型 (他の型のメンバーになっている型):規定のアクセシビリティと宣言できるアクセシビリティは次の表の通りです。
他の型(=入れ子の親) | メンバーの既定のアクセシビリティ | メンバーに対して宣言できるアクセシビリティ |
---|---|---|
enum | public | なし |
class | private | public protected internal private protected internal private protected |
interface | public | public protected internal private (※)protected internal private protected |
struct | private | public internal private |
private
アクセシビリティを持つ interface
メンバーには、既定の実装が必要です。ただし、入れ子にされた型(メンバー)のアクセシビリティレベルが、その型を含んでいる親の型のアクセシビリティレベルを上回ることはできません。Visual Studioでもきちんとエラーになります。
各アクセス修飾子の利点と具体的な使用例
public
public
修飾子は、最もアクセスレベルが高い修飾子です。public
に設定されたメンバーは、どこからでもアクセス可能です。
public class MyClass
{
public int MyField; // 他のクラスからアクセス可能
public void Display()
{
Console.WriteLine("Field value: " + MyField);
}
}
// 外部クラスからのアクセス例
public class Program
{
public static void Main()
{
MyClass obj = new MyClass();
obj.MyField = 10;
obj.Display(); // 出力: Field value: 10
}
}
利点
- クラスやメソッドを広く共有する場合に便利。
- 他の開発者が簡単に利用できるようになります。
使用例
ライブラリを作成し、他のプロジェクトで再利用する場合、public
メソッドやプロパティを提供することで、利用者が簡単に機能を呼び出すことができます。
private
private
修飾子は、クラス内でのみアクセス可能なメンバーを定義します。最も制限の厳しいアクセスレベルです。
public class MyClass
{
private int MyField; // 同じクラス内でのみアクセス可能
public void SetField(int value)
{
MyField = value;
}
public int GetField()
{
return MyField;
}
public void Display()
{
Console.WriteLine("Field value: " + MyField);
}
}
// 外部クラスからのアクセス例
public class Program
{
public static void Main()
{
MyClass obj = new MyClass();
obj.SetField(10);
obj.Display(); // 出力: Field value: 10
// obj.MyField = 10; // エラーになる
}
}
利点
- クラス内部のデータを保護し、外部からの不正アクセスを防ぎます。
- カプセル化を促進し、コードのメンテナンス性を向上させます。
使用例
クラス外部に公開しない内部データや実装の詳細を隠蔽したい場合、private
メンバーを使用することで外部からのアクセスを制限できます。
protected
protected
修飾子は、同じクラスまたはその派生クラスからアクセス可能なメンバーを定義します。
public class Animal
{
protected string Name;
public Animal(string name)
{
Name = name;
}
public void Display()
{
Console.WriteLine("Name: " + Name);
}
}
public class Dog : Animal
{
public Dog(string name) : base(name)
{
}
public void Bark()
{
Console.WriteLine(Name + " is barking!");
}
}
// 外部クラスからのアクセス例
public class Program
{
public static void Main()
{
Dog dog = new Dog("Buddy");
dog.Display(); // 出力: Name: Buddy
dog.Bark(); // 出力: Buddy is barking!
}
}
利点
- 継承関係にあるクラス間でデータを共有できます。
- カプセル化を保ちながら、柔軟な設計が可能です。
使用例
基本クラスで定義されたデータを派生クラスで利用する場合、protected
メンバーを使用することで、派生クラスからのみアクセスできます。
internal
internal
修飾子は、同一アセンブリ内でアクセス可能なメンバーを定義します。
internal class MyClass
{
internal int MyField; // 同じアセンブリ内からアクセス可能
internal void Display()
{
Console.WriteLine("Field value: " + MyField);
}
}
// 同じアセンブリ内の他のクラスからのアクセス例
public class Program
{
public static void Main()
{
MyClass obj = new MyClass();
obj.MyField = 10;
obj.Display(); // 出力: Field value: 10
}
}
利点
- アセンブリ内でのデータ共有が可能。
- 他のプロジェクトからのアクセスを制限することで、セキュリティを向上させます。
使用例
他のプロジェクトで使用するライブラリの内部で使用する内部クラスやメソッドを定義する場合、internal
修飾子を使用することで他のアセンブリからのアクセスを制限できます。
protected internal
protected internal
修飾子は、同一アセンブリ内および派生クラスからアクセス可能なメンバーを定義します。
public class BaseClass
{
protected internal int MyField;
public BaseClass(int value)
{
MyField = value;
}
public void Display()
{
Console.WriteLine("Field value: " + MyField);
}
}
public class DerivedClass : BaseClass
{
public DerivedClass(int value) : base(value)
{
}
public void ModifyField(int newValue)
{
MyField = newValue;
}
}
// 同じアセンブリ内の他のクラスからのアクセス例
public class Program
{
public static void Main()
{
DerivedClass obj = new DerivedClass(10);
obj.Display(); // 出力: Field value: 10
obj.ModifyField(20);
obj.Display(); // 出力: Field value: 20
}
}
利点
- 高い柔軟性を持つアクセス修飾子。
- 内部データの共有と継承を同時に実現。
使用例
ライブラリ内で使用する基本クラスを定義し、そのクラスを他のアセンブリ内で派生クラスとして拡張する場合、protected internal
修飾子を使用することで、柔軟なアクセス制御が可能です。
private protected
private protected
修飾子は、定義されたクラス内、または同じアセンブリ内の派生クラスからアクセス可能なメンバーを定義します。
public class BaseClass
{
// private protected メンバー
private protected int MyField;
public BaseClass(int value)
{
MyField = value;
}
// private protected メソッド
private protected void Display()
{
Console.WriteLine("Field value: " + MyField);
}
}
// 同じアセンブリ内の派生クラス
public class DerivedClass : BaseClass
{
public DerivedClass(int value) : base(value)
{
}
public void ShowField()
{
// private protected メンバーにアクセス可能
Console.WriteLine("Member: " + MyField);
// private protected メソッドを呼び出し
Display();
}
}
// 外部クラスからのアクセス例
public class Program
{
public static void Main()
{
DerivedClass obj = new DerivedClass(10);
obj.ShowField(); // 出力: Member: 10、Field value: 10
// obj.MyField = 20; // エラーになる
// obj.Display(); // エラーになる
}
}
利点
- アセンブリ内の特定のクラスからのアクセスを制限しながら、継承を許可します。
- 内部の実装詳細をより厳密に制御できます。
使用例
ライブラリ内で特定の機能を提供し、アセンブリ内の派生クラスでのみその機能を拡張したい場合、private protected
修飾子を使用することで、厳密なアクセス制御が可能です。
まとめ
今回は、C#のアクセス修飾子について解説させていただきました。アクセス修飾子を使いこなすことで、C#のコード設計がより洗練されます。
アクセス修飾子について理解を深め、効果的に活用することで、より堅牢でメンテナンス性の高いコードを作成しましょう!この記事が皆さんのプログラミングライフに役立つことを願っています。