LoginSignup
86
51

More than 3 years have passed since last update.

C#のアクセス修飾子 2019 〜protectedは 結構でかい〜

Last updated at Posted at 2019-12-03

この投稿では、2019年におけるC#のアクセス修飾子を紹介します。

C# 7.2から新たにprivate protectedが新たに加わりました。これは、『「同一のアセンブリ」 かつ 「その型とその派生型」はアクセスできる』というアクセスレベルです。そしてゲームエンジンUnityにAssembly Definition FilesPackage Managerが加わったことで、Unity開発者は「アセンブリ」を意識して開発する機会が増えました。継続的なライブラリ更新のために、このようなアセンブリに関係するアクセス修飾子をしっかりと理解すべき状況となっています。

自分で開発したライブラリを社内で公開している人、世の中に広く公開したい人は、2019年におけるC#のアクセス修飾子理解することをオススメします。

アクセス修飾子とアクセスレベル

アクセス修飾子は以下の4個です

  • public
  • protected
  • internal
  • private

アクセスレベルは以下の6種です。

  • public : 無制限
  • protected : その型とその派生型はアクセスできる
  • internal : 同一のアセンブリ(同じDllやExe)からのみアクセスできる
  • protected internal : 「同一のアセンブリ」 もしくは 「その型とその派生型」はアクセスできる
  • private protected: 「同一のアセンブリ」 でありかつ 「その型とその派生型」はアクセスできる
  • private : その型からのみアクセスできる

private protectedがC# 7.2から新たに加わったアクセスレベルです。
※ 中間言語のMSILとして「protected and internal」相当のものは以前から存在していましたが、C#で加わったのはC# 7.2からです。

protectedはでかい。なぜなら・・・

ライブラリ開発者にとって、アクセスレベルprotectedは非常にアクセス範囲が広いアクセスレベルです。

『あなたはライブラリ開発者で、コード形式ではなくアセンブリ(DLL形式)でライブラリを配布しており、あるAPIを削除しようとしています。』このような状況を考えてみてください。

  • 削除しようとしているAPIがprivateアクセスレベルだったら、そのAPIは問題なく削除できます。ライブラリ利用者はprivateメンバにアクセスできないからです。

  • 削除しようとしているAPIがinternalアクセスレベルだったら、そのAPIは問題なく削除できますね。ライブラリ利用者はinternalなメンバ・型にアクセスできないからです。

  • 削除しようとしているAPIがpublicアクセスレベルだったら、そのAPIを削除した場合破壊的変更になってしまうので、簡単に削除できません。Obsoleteにし移行方法をアナウンスするなどコストをかける必要があります。(もしくは、いきなり削除してライブラリ利用者に迷惑をかけるしかありません)

では、削除しようとしているAPIがprotectedアクセスレベルだった場合はどうでしょう?ライブラリ開発において、protectedアクセスレベルは、publicアクセスレベルと同等に慎重に扱わないといけません。protectedアクセスレベルは、「その型とその派生型はアクセスできる」ですが、派生された型であればライブラリ利用者は自由に使うことができます。そのため、protected APIを削除することは破壊的な変更になってしまいます。publicアクセスレベルのAPIと同様に、Obsoleteにし移行方法をアナウンスするなどコストをかける必要があります。(もしくは、いきなり削除してライブラリ利用者に迷惑をかける覚悟を持つ必要があります。)

次にprotected internalアクセスレベルです。protected internalアクセスレベルは「同一のアセンブリ」 もしくは 「その型とその派生型」はアクセスできます。そのため、ライブラリ利用者は派生された型の内部でprotected internalなメンバにアクセスできます。そのため、protected internalなAPIを削除することは破壊的な変更になってしまいます。これもpublicアクセスレベルと同等に慎重に扱わないといけません。

では、C# 7.2から加わったprivate protectedアクセスレベルはどうでしょうか?これは、「同一のアセンブリ」 でありかつ 「その型とその派生型」はアクセスできるというアクセスレベルです。ライブラリ利用者はprotected internalなメンバにアクセスすることができません。「同一のアセンブリ」ではないからです。そのため、そのAPIは問題なく削除できます。

おさらいしましょう。

アセンブリ(DLL形式)でライブラリを配布しているのであれば、

  • public
  • protected
  • protected internal

なアクセスレベルメンバ・型の削除は、破壊的な変更になってしまうので簡単には削除できません。Obsoleteにし移行方法をアナウンスするなどコストをかける必要があります。(もしくは、いきなり削除してライブラリ利用者に迷惑をかけるしかありません)

protectedそして、protected internalは実は結構アクセス範囲が広いということに注意してください。

protected internalは、『「同一のアセンブリ」 または 「その型とその派生型」はアクセスできる』であり、『「同一のアセンブリ」 かつ 「その型とその派生型」はアクセスできる』ではないことに注意してください。

※ これはライブラリの話であり、アプリケーションの話とは違うのでその点に注意してください。
※ ベータ版など、破壊的な変更が入る予定があるライブラリもたくさんあります。

リフレクションを使えばprivateメンバにもアクセスできる

リフレクションを使えばprivateメンバにアクセスできます。

ライブラリ利用者に対して、どうしても隠しておかないといけない情報はprivateにしたとしても、リフレクションを使えばアクセスできます。この点に注意してください。

アクセス修飾の順番

private protected は、protected privateと同じ意味です。

また、protected internalinternal protectedと同じ意味です。

これらは修飾子の順番を変えても有効です。

interanalな型をテストしたい場合

interanalな型を別アセンブリのテストプロジェクトでテストしたい場合、InternalsVisibleToAttributeを活用しましょう。

その他いろいろ

アクセス修飾子を省略した場合や、入れ子の型のアクセス修飾子については、公式ドキュンメントをみてください。

関連

補足

この記事は、

  • Unity 2019.2
  • C# 8

までの仕様です。

86
51
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
86
51