UnityC#のフィールド・プロパティ・アクセス修飾子の使い方 スコープの概念を理解する

フィールドとプロパティについての画像 Unity C#入門講座
フィールドとプロパティはクラスが持つ変数。


Unityの本格ゲーム制作講座はこちら
【30日間の全額返金保証付き】

今回の記事ではクラスのメンバであるフィールドとプロパティをまず解説し、次にアクセス修飾子とスコープについての理解を深めていきます。

ややこしいところですが、頑張っていきましょう!

前回の記事:

UnityC# クラスとインスタンスの作り方・コンストラクタの使い方
今回の記事ではクラスについて解説していきます。 クラスについては複数回に分けて解説します。今回はクラスとインスタンスの基本的な使い方について解説します。 ちなみに構造体(struct)も大体クラスと同じものになり、ここで解説する用法は構...

【Unity入門の森の最新ゲーム開発講座もお届け】

クラスにフィールドとプロパティを持たせてみよう

それではフィールドとプロパティについて解説していきます。

この2つのメンバはクラスが持つ変数になります。

フィールド(Field)とは

フィールドとはの画像

フィールドはクラスが持つ変数になる。

フィールド(Field)とはクラスが持つ変数になります。

プロパティ(Property)とは

プロパティとはの画像

プロパティはクラスが持つ変数みたいなものになる。
メソッドを介してクラスのメンバにアクセスする。

プロパティ(Property)とはフィールドと同じくクラスが持つ変数のようなものですが、フィールドとは異なり一度メソッドを介してクラスのメンバにアクセスします。

プロパティにはsetメソッドとgetメソッドをそれぞれ定義することができます。両方とも定義する必要はなくどちらか片方のみでもOKす。

  • setメソッド:値を設定する時に呼び出される。設定される値はvalueという特殊な変数に保存される。
  • getメソッド:値を取得する時に呼び出される。

setメソッドを定義する時、設定される値valueという特殊な変数の中に代入されていますので、そちらを使用してください。

基本的に上であげたメソッドを定義する必要がありますが、自動プロパティという省略記法を使うとフィールドのように使うことができます。自動プロパティの時はsetget両方書かないといけません。

<型名> <プロパティ名> { get; set; }

アクセス修飾子とは?

アクセス修飾子とはの画像

アクセス修飾子はクラスのメンバの使用範囲を指定するもの。何も付けないのもアクセス修飾子の一つになる。

C#にはアクセス修飾子というメンバの使用範囲を指定する機能があります。

プロパティの場合はsetgetメソッドそれぞれ異なるアクセス修飾子を付けられます。

<アクセス修飾子> <メンバ宣言・定義>

アクセス修飾子には以下のものがあります。

  • public:どこからでもアクセスできる。
  • protected:自身と継承したクラスからアクセスできる。
  • internal:同じアセンブリ内からしかアクセスできない
  • protected internal:自身または同じアセンブリ内か、このクラスを継承したクラスからアクセスできる。
  • private protected:自身またはこのクラスを継承したクラスからしかアクセスできない。
  • private:宣言したクラスからしかアクセスできない。何も付けない場合もprivateになります。

アセンブリという用語が出てきましたが、これはコンパイルによって生成されたDLLファイルや実行ファイルなどを指します。C#ではアセンブリ単位でクラスのメンバのアクセス範囲を区切ることができます。visual studioを使う場合、1プロジェクトが1アセンブリとなるため、internalは同一プロジェクトでアクセス可能となります。

変数やフィールド、プロパティにあるスコープ(Scope)って何?

スコープとはの画像

スコープは変数やプロパティなどの使用範囲を表すもの。

ここまで意識することはあまりなかったのですが、変数およびクラスのメンバにはそれを宣言・初期化した部分によって使用する範囲が決められています。これにはアクセス修飾子も関係するのですが、それ以外のルールも存在しますのでそれについて解説していきます。

例えば、メソッド内で宣言した変数はそのメソッド内でしか使用することができません。この変数をローカル変数といいます。

この変数を使える範囲のことをプログラミングの世界ではスコープ(Scope)と呼びます。

あるスコープ内では同じ名前のものは必ず一つになるようにする必要があります。型が異なる時でも同じ名前だとコンパイルエラーになるので注意しましょう!

ただし、メソッドやクラス名など文脈上異なるものだとわかる場合は同じ名前でも問題ありません。また、メンバと引数は同じ名前でも問題ありません。その場合は引数が優先して使われます。

変数およびフィールド、プロパティのスコープは次のものがあります。上にあるものほど使用範囲が広くなります。また、これに加えアクセス修飾子による使用範囲の制限も設けられます。

  1. クラスの静的メンバ(※1)フィールド、プロパティ
  2. クラスのインスタンスメンバフィールド、プロパティ
  3. メソッドの引数
  4. メソッド内で宣言・初期化したローカル変数
  5. メソッド内で一段階ネスト(※2)した中のローカル変数
  6. 以降、ネストするたびにスコープは小さくなる。

(※1静的メンバについてはこの次の項目をご覧ください。)

(※2鉤括弧でブロック分けすること。if文やfor文などの鉤括弧も含まれる。)

静的(static)メンバとは

静的メンバはstatic修飾子をつけたメンバのことで、使用する時にインスタンスは不要で代わりにクラス名をつけるメンバになります。静的メンバはプログラムのどこからでも使用することができます。

一般的にスコープが広いほどプログラムに影響する範囲が広くなりますので、極力スコープが小さくなるようにメンバを使っていきましょう!

【実践】Unityでスコープの違いを体験してみよう

それでは今回の記事でクラスのフィールドとプロパティについて解説したので実際に使ってみましょう!

と言いたいところですが、これまでの記事のコンポーネントの中で既に使ってきているのでここではスコープについて体験してみましょう!

今回のサンプルはスクリプトの内容がメインになりますので、スクリプトの内容を読んでどのメンバが使用できてどのメンバが使用できないかを見分けられるか試してみましょう!

アクセス修飾子によって使用できるメンバに制限がかかるのを体験してみよう!

次のサンプルコードではアクセス修飾子によってメンバの使用に制限がかかるのを体験できる作りになっています。

SampleコンポーネントのDataクラスには_speedフィールドとそれにアクセスするためのSpeedプロパティがあります。

  • _speedフィールド:何もアクセス修飾子がついていない(=private扱い)のでクラス内でしか使用できない。
  • Speedプロパティ:publicアクセス修飾子がついているのでクラス外からでも使用できる。

これらのDataクラスのメンバをUpdate()メソッド内で使用していますが、コンパイルエラーになるものにはNGとコメントしています。そのコメントを外すとコンパイル時にエラーが発生するので確認してみてください。

サンプル1スコープについての画像

以前の記事と同じ様に再生するとGameObjectが左右に動く。 サンプルコードのコメント部分を有効にしたりしなかったりして、アクセス修飾子によるメンバの使用範囲の違いを確認してみてください。

Serialized Field(UnityEngine.SerializeFieldAttribute)について

また、上のサンプルコードではSerializeField(UnityEngine.SerializeFieldAttribute)という属性をData._speedフィールドに付けています。

UnityエディタではpublicなフィールドしかInspectorから設定できないのですが、この属性をつけることでそれ以外のアクセス修飾子がついたフィールドでも設定できるようになります。

プロパティの場合はUnityエディタが対応していないため、Inspectorから設定できません(エディタ拡張を使用すると無理やり設定することもできますが、基本的にフィールドのみを対象にした方がいいでしょう。)

ブロックによって異なるスコープになるのを体験してみよう!

次のサンプルコードでは2つの色を足し合わせてMeshに設定するものになります。

2つの色を足す際にそれぞれの色をちょっとづつ変えているのですが、その部分で同じ名前のローカル変数(color)を使用しています。このcolor変数は各ブロックで異なる変数として扱われていることに注目してください。

ブロックによるスコープの差を体験するためのものです。あまり実践的ではないサンプルになっていますがお許しください。

サンプル2ブロックによるスコープの違いの画像

サンプルを実行するとColor1とColor2を少し編集したものを足し合わせた色になる。Start()の中でブロック分けにして色を足している部分に注目。 colorというローカル変数が2つ宣言されているがブロック分けしているのでコンパイルできる。

まとめ

ここまでフィールドとプロパティについてみてきました。

今回の記事をまとめると以下になります。

  • フィールドとはクラスが持つ変数
  • プロパティとはクラスが持つフィールドを便利にしたもの。
  • クラスのメンバには使用範囲を表すアクセス修飾子をつけることができる。
  • 変数やフィールド、プロパティには現在実行中の処理から使用できるかどうか表すスコープが存在する。
  • 同じスコープ内には同じ名前の変数、フィールド、プロパティは一つしか存在できない。
  • 処理をブロックで分ける(鉤括弧{}で括る)とスコープの管理ができる。
  • クラスには静的メンバというアプリのどこからでもアクセスすることができるメンバがある。
  • UnityEngine.SerializeFieldAttributeをフィールドに指定するとpublicではなくてもInspectorから値を設定することができる。

それでは次の記事に行ってみましょう!

UnityC# クラスの継承・抽象メソッドとオーバライドの使い方
今回の記事ではクラスの継承についてみていきます。 Unityではコンポーネント自体がUnityEngine.MoneBehaviourを継承したものなので実は既に使用している機能になります。 さらにUnityEngine.MonoBeh...

初心者向けUnityC#入門講座に戻る>>


【Unity入門の森の最新ゲーム開発講座もお届け】

コメント

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