メソッド
オブジェクトの振る舞い
フィールドはインスタンスの状態を表すデータであり、オブジェクトの性質を保存する変数の一種です。オブジェクトの振る舞い(動作)を記述するにはメソッド(method)を用います。メソッドはフィールドと同様にクラスに含まれるメンバです。
メソッドは C 言語などの手続き型言語における関数やサブルーチンに相当する機能を提供します。 ただし、メソッドは関数と異なりクラスのメンバであり、オブジェクトの動作を表現するために用いられます。多くのメソッドは、所属するクラスのオブジェクトの状態を更新や、他のオブジェクトとの対話に関連した処理を書くことになるでしょう。
メソッドはメソッド宣言(method declaration)によって記述します。メソッド宣言のすべての構文は少し複雑になりますが、基本的な書き方は以下のような形になります。
メソッド修飾子 戻り値型 メソッド名 (パラメータリスト) { メソッド本体 }
メソッド修飾子(method modifiers)はフィールドと同様にアクセス制御などの修飾子を指定するものです。メソッド修飾子は省略可能ですが、クラスの外部から呼び出すメソッドに対しては public 修飾子を指定しなければなりません。
戻り値型(return type)にはメソッドが返す値の型を指定します。例えば整数を返すメソッドは戻り値型に int を指定することになります。戻り値を返さないメソッドを宣言する場合、戻り値型には void キーワードを指定します。
パラメータリスト(formal-parameter-list)はメソッドが受け取るパラメータをカンマ区切りで指定したリストです。パラメータを受け取らない場合、パラメータリストは省略可能です。パラメータについては後述するので、最初はパラメータと戻り値のない簡単なメソッドを作りましょう。
メソッド名は宣言するメソッドを識別するためのメンバ名(member name)を指定します。クラスや変数と同じ命名規則で、メソッドの呼び出しにメソッド名が必要になります。通常、メソッドはオブジェクトの振る舞いを表すため動詞で名づけます。
メソッド本体(method body)は中括弧 { } からなるブロック文そのものです。これまで Main() メソッド内に書いてきた内容と同じように、内部に任意の実行コードを記述できます。メソッドが呼び出されたとき、メソッドはメソッド本体に記述されているブロックを実行します。
エントリーポイントである Main() メソッドはアプリケーション実行時に自動的に呼び出されますが、それ以外のメソッドは宣言しただけでは実行されません。メソッドを実行するには、呼び出し式(invocation expression)を用いてメソッドを呼び出す必要があります。
メソッド (引数リスト)
呼び出し式の左項には呼び出すメソッドを指定します。メソッドの実行はメソッドが宣言されているクラスのインスタンスに関連付けられています。したがって、外部のクラスからメソッドを呼び出すには、フィールドと同様にメンバアクセスを用いてメソッドを指定しなければなりません。
メソッドがパラメータを宣言している場合、メソッドを呼び出すときにパラメータに対応する値を設定しなければなりません。このとき、メソッドのパラメータに渡す値のことを引数(argument)と呼びます。呼び出し式の引数リスト(argument-list)には、カンマ区切りでパラメータに渡す引数を指定します。メソッドがパラメータを持たない場合、引数リストは省略可能です。
呼び出し式の結果はメソッドの戻り値であり、呼び出し式の型はメソッドの戻り値型に一致します。戻り値型が void の場合、呼び出し式の結果はありません。
これまで、テキストを出力するために用いてきた WriteLine() もメソッドであり、呼び出し式を使って呼び出していました。独自に開発したメソッドを呼び出す場合も同じです。まずは、パラメータを持たず、結果を返さない、単純なメソッドを作成してみましょう。
class MagicalGirl { public void Attack() { System.Console.WriteLine("ティロ・フィナーレ"); } } class Test { public static void Main(string[] args) { MagicalGirl mami = new MagicalGirl(); mami.Attack(); } }
コード1の MagicalGirl クラスは、パラメータも戻り値もない Attack() メソッドを宣言しています。Main() メソッドで MagicalGirl クラスのインスタンスを作成し、呼び出し式を用いて Attack() メソッドを呼び出しています。Attack() メソッド内では、単に WriteLine() メソッドでテキストを出力しています。実行結果を見れば、正しく Attack() メソッド内のコードが実行されていることが確認できます。
メソッドの呼び出しにはオブジェクトが必要であり、メソッドは呼び出しに使用されたオブジェクトに関連付けられています。従って、メソッド内のコードは自分自身のオブジェクトが持つフィールドや他のメソッドといったメンバにアクセスできます。
class MagicalGirl { public string name; public string specialAttack; public void Attack() { System.Console.WriteLine(name + ": " + specialAttack); } } class Test { public static void Main(string[] args) { MagicalGirl nanoha = new MagicalGirl(); nanoha.name = "高町なのは"; nanoha.specialAttack = "スターライトブレイカー"; nanoha.Attack(); } }
コード2の MagicalGirl クラスは name フィールドと specialAttack フィールドを持ち、これらのフィールドに保存されている文字列を Attack() メソッドで出力します。
Test クラスは MagicalGirl クラスではないため、ここから MagicalGirl クラスのメンバを利用するには new 演算子でインスタンス化したオブジェクトからメンバアクセスしなければなりません。しかし、MagicalGirl クラスのメンバである Attack() メソッドからは、メンバ名だけで name フィールドや specialAttack フィールドにアクセスできます。
パラメータと戻り値
前述したように、メソッドは値を受け取り、値を返すことができます。例えば、2 つの値を受けとって何らかの計算を行い、計算結果を返すメソッドを作れます。こうすれば、メソッドに値を渡すだけで計算処理はメソッドに任せることができます。
メソッドが呼び出し元から値を受け取るには、メソッド宣言のパラメータリストに、受け取る値の型とパラメータ名を指定します。パラメータの宣言は、基本的に変数宣言と同じです。メソッド内で、パラメータはローカル変数と同様に作用します。
public void Add(int a, int b) { System.Console.WriteLine(a + b); }
上記の Add() メソッドは 2 つの int 型のパラメータを受け取り、それらを加算した結果を出力するというものです。このメソッドを呼び出すには a パラメータと b パラメータに渡す引数を指定しなければなりません。例えば、以下のコードは a パラメータに 10 を、b パラメータに 20 を渡します。
Add(10, 20);
この結果 Add() メソッドは 30 という結果を表示するでしょう。メソッドを呼び出すときに渡した引数によって、メソッドの処理内容が変化するようになります。
class MagicalGirl { public string name; public string specialAttack; public void AttackWith(MagicalGirl supporter) { System.Console.WriteLine(supporter.name + "の支援: " + supporter.specialAttack); System.Console.WriteLine(name + ": " + specialAttack); } } class Test { public static void Main(string[] args) { MagicalGirl nanoha = new MagicalGirl(); nanoha.name = "高町なのは"; nanoha.specialAttack = "ディバインバスター"; MagicalGirl fate = new MagicalGirl(); fate.name = "フェイト・テスタロッサ"; fate.specialAttack = "サンダースラッシュ"; nanoha.AttackWith(fate); } }
コード3の MagicalGirl クラスの AttackWith() メソッドは supporter パラメータに別の MagicalGirl オブジェクトを受け取り、supporter オブジェクトのフィールドと、自分自身のフィールドに保存されている文字列を出力しています。
void 以外の戻り値型で宣言されているメソッドは、戻り値型に指定されている値を返さなければなりません。メソッドが戻り値を持つ場合、メソッドを終了するときに return 文を必ず用います。return 文が実行されない流れがある場合はエラーとなるので注意してください。
public int Add(int a, int b) { return a + b; }
上記の Add() メソッドは int 型の a パラメータと b パラメータを加算した結果を返します。このメソッドを呼び出すコードは、メソッドの結果を受け取ることができます。メソッドの呼び出しそのものが、式の中では int 型として扱われます。
int r = Add(10, 20);
上記のように Add() メソッドを呼び出せば、パラメータに渡した 2 つの値が加算された結果が得られるでしょう。よって r 変数には 30 が格納されます。ただし、メソッドの戻り値を無視することもできます。変数などで受け取らず、ただ呼び出すだけでも問題はありません。その場合、戻り値で返された値は破棄されます。
class Girl { public string name; } class Incubator { public string name; public MagicalGirl ContractWith(Girl girl) { MagicalGirl r = new MagicalGirl(); r.girl = girl; r.gift = "レイジングハート"; System.Console.WriteLine(girl.name + "が" + name + "と契約しました"); return r; } } class MagicalGirl { public Girl girl; public string gift; } class Test { public static void Main(string[] args) { Girl nanoha = new Girl(); nanoha.name = "高町なのは"; Incubator yuno = new Incubator(); yuno.name = "ユーノ・スクライア"; MagicalGirl lyricalNanoha = yuno.ContractWith(nanoha); System.Console.WriteLine("魔法少女: " + lyricalNanoha.girl.name); System.Console.WriteLine("ギフト: " + lyricalNanoha.gift); } }
コード4の Incubator クラスにある ContractWith() メソッドは Girl クラスと自分自身の情報から、MagicalGirl オブジェクトを生成して返すというシナリオです。ContractWith() メソッドの girl パラメータに渡された Girl クラスのオブジェクトは、生成される MagicalGirl クラスの girl フィールドに設定されます。ContractWith() メソッドの戻り値は、メソッド内で生成された MagicalGirl オブジェクトです。
Main() メソッドでは Girl オブジェクトと Incubator オブジェクトを生成し、その後 ContractWith() メソッドを呼び出し、その結果をして MagicalGirl オブジェクトを受け取っています。