Continuousで始めるC# / Xamarin 003 : Hello World
C#のザックリ解説
ちゃんとC#を勉強するには本を1冊以上読むことになるかと思いますが、ここでは、プログラミング経験のある方向けに、C#の雰囲気を見てもらうレベルのザックリ解説を行います。
C#は、JavaとかC++とかObject Pascalとかに影響を受けている言語とされています ( Object Pascalって何?とか言わない )。文法は、既存の言語に合わせられる部分はそのまま流用している感じで、経験のある方なら基本的なところはすんなりと理解できるのではないかと思われます。
HELLO WORLDしてみる
HELLO WORLDは以下のような感じになります。この後、アドレス帳っぽい感じにしていくので、クラス名などはそういう名前にしています。
// 基本のライブラリを使用 *1 using System; // アプリのコードはこの名前空間に入れる *2 namespace App { // アドレス帳アプリのクラス定義 *3 public class AddressBookApp { // Mainが実行される *4 public static void Main( string[] args ) { // コンソール出力 *5 Console.WriteLine( "HELLO WORLD" ); } } }
とりあえず、コンソールに文字列を出すだけですので、細かい説明は後回しで構成を見ていきます。
- 1 : usingはライブラリの使用の宣言でもありますが、オブジェクト名を簡潔に書くためのものでもあります。例えば、コンソール出力は、System.Console.WriteLineですが、Systemが省略可能となります。
- 2 : namespaceで名前空間を宣言しています。クラス名等の衝突を避けるための殼を作ることができます。関連するクラスの定義をまとめるためのものでもあります。
- 3 : アドレス帳アプリのクラスの定義をここに定義します。クラスの定義は public class CLASS_NAMEのように書きます。外から見えなくしたければpublicのところをprivateにします。継承したいクラスは今回ないので省略しています。といっても、省略するとルートクラスのObjectを継承します。
- 4 : Mainメソッドを書いておくと、ここから実行されます。
- 5 : Console.WriteLineでコンソール出力します。自動で改行されます。
独自クラスを作ってみる
アプリの外枠を作りましたので、アドレス帳を管理するライブラリとしてAddressBookKitというのを作ります。
using System; // アドレス帳のライブラリを使う using AddressBookKit; // アドレス帳のライブラリ namespace AddressBookKit { // Personクラスの定義 *1 public class Person { // フィールドの宣言 *2 public string FirstName; public string LastName; public string BloodType; // コンストラクタの定義 *3 public Person( string firstName, string lastName, string bloodType ) { // 中身を初期化 FirstName = firstName; LastName = lastName; BloodType = bloodType; } // インスタンスメソッドの定義 *4 public string GetFullName() { // 文字列生成 *5 return String.Format( "{0} {1}", FirstName, LastName ); } } } // アドレス帳アプリ本体 namespace App { public class AddressBookApp { public static void Main( string[] args ) { // Personクラスのインスタンス生成 *6 Person p1 = new Person( "Hanako", "Yamada", "B"; ); // フィールドを変更 *7 p1.FirstName = "Taro"; p1.LastName = "Suzuki"; // メソッド呼び出し *8 Console.WriteLine( "FullName={0}", p1.GetFullName() ); } } }
- 1 : 人のデータを扱うPersonクラスを作っていきます。変数宣言は、TYPE NAME のように書きます。
- 2 : オブジェクトの中に情報を保存するにはフィールドを宣言します。public string FIELD _NAMEのように書きます。publicのところはクラスと同じです。stringは、フィールドの型で文字列を表します。整数ならintになります。
- 3 : インスタンスを生成するためのコンストラクタは、クラス名と同じ名前のメソッドとして定義します。public CLASS_NAMEで始まり、引数リスト、処理の中身が続きます。メソッド名の前には、通常、そのメソッドの返り値の型を書きますが、コンストラクタの場合はそのクラスだと決まっているため不要です。
- 6 : 先にコンストラクタを呼んでいるところを見てみますと、new CLASS_NAMEに続いて引数リストを書くことでインスタンスを生成できます。
- 4 : インスタンスのメソッドを1つ定義してみます。GetFullNameというフルネームを返すものです。
- 5 : String.Formatというのは書式指定で文字列を生成するメソッドです。{N}は、文字列の後ろにある値を埋め込む場所で、Nには何番目の値を使うかを書きます。{0}だと、文字列の直後のFirstNameの中身に置き換わります。この書式指定はConsole.WriteLineでも使えます。
- 7 : 生成したインスタンスのフィールドのアクセスにはドットをつけてフィールド名を書きます。
- 8 : メソッド呼び出しも、ドットをつけてメソッド名。その後ろに引数リストを書きます。
大体、どこかで見たことあるような文法ばかりですね(個人的感想)。
引数のデフォルト値
クラスにメソッドを色々と実装する際に、機能は同じでも、簡単に使える引数の少ないメソッドと、詳細を指定できる引数の多いメソッドを用意したくなります。でも、何通り作ればいいのか悩みますよね。
C#では、メソッドを呼び出す時に引数を省略してもいいような仕組みを持っています。省略された引数に対してデフォルト値をメソッド側で決めておくことができるのです。
以下のように引数のデフォルト値をイコールの後ろに書きます。
// デフォルト値指定付きの引数 *1 public Person( string firstName = "unknown", string lastName = "unknown", string bloodType = "unknown"; ) { FirstName = firstName; LastName = lastName; BloodType = bloodType; }
呼び側は以下のように引数の名前を書きます。名前がないと、どれが省略されたか分からないからですね。
Person p1 = new Person( firstName : "Hanako", lastName : "Yamada" );
引数に名前を付けた方が可読性が上がるというメリットもあります。
名前があるため、引数の順番を変えても問題ありません。名前を付けているということで、引数リストというより、引数辞書という感じですね。
Person p3 = new Person( lastName : "Sato", firstName : "Jiro" );
プロパティ
先程、GetFullNameというメソッドを定義しましたが、メソッドだと、呼び出し側はp1.GetFullName()のように末尾に括弧をつけて呼ぶことになります。でも、このような単なる情報取得の場合は、フィールドにアクセスする感じでp1.FullNameのように書けるとスマートです。
これを実現するための仕組みがプロパティです。中身はメソッドですが、呼び側から見るとフィールドのように見えます。
プロパティの定義は、メソッドの定義のような書き始めになりますが、引数リストがありません。取得用のメソッドはget { ... }のように書きます。
public string FullName { get { return String.Format( "{0} {1}", FirstName, LastName ); } }
これでp1.FullNameが使えるようになります。
Personクラスに年齢の情報を追加したとします。単にフィールドで追加してもいいですが、マイナスの値がセットされないようにしたいなどの処理が必要な場合はメソッドになりますよね。
これをプロパティを使うと次のようになります。
public class Person { : int age; // フィールドの宣言 *1 // プロパティの定義 *2 public int Age { get { return age; } set { if ( 0 <= value ) { age = value; } } } }
- 1 : 値を保持するフィールドを宣言します。プロパティ経由でこのフィールドを書き換えますので、privateにします。デフォルトがprivateなので、何も書かないとprivateになります。
- 2 : プロパティの定義のですが、値をセットする方はset { ... } のように書きます。valueという変数には、セットされる値、つまり代入文の右辺の値が入っています。
呼び側は以下のようになります。メソッドを呼んでいるのですが、フィールドへの代入のように書けます。
p1.Age = 10;
自動プロパティ
プロパティを知ってしまうとフィールドはあまり使いたくなくなるかもしれません。でも、全てのフィールドに同じコード書くのも面倒ですよね。そのため、短く書ける記法が用意されています。
public string Address { get; set; } // *1 public string BloodType { get; private set; } // *2
- 1 : { get; set; } と書くだけでよく、値を格納するためのprivateなフィールドの宣言も不要です。意識する必要はありませんが、内部的にフィールドが自動生成されます。
- 2 : クラスの中からはセット可能で、外部からはセットはできないプロパティは、private set とします。例えば、血液型は後からは変わらないので、コンストラクタでのみ値が指定できるようにしたい場合に使えます。何らかのidなどで変えられないようにしたいとかですね。
なんかこう、Swiftに似てるよね(逆)。