第12章 C#の布教

74回生 cobalt

こんにちは、cobaltです。私はC#というプログラミング言語が大好きなので、C#について書いていこうと思います

12.1 まずプログラミング言語って何

プログラミング言語とは、コンピューター(この場合はスマートフォンなんかも含みます)に命令するために作られた人工言語です。長い歴史(70年ほど)と多くの種類があり、コンピューターの扱う2進数に近いものや、人間の扱う言葉に近いもの、3種類の言葉しか使わないものなど色々な種類があります。

12.2 じゃあC#って何

C#は、アンダース・ヘルスバーグというプログラマが設計した言語で、Cという言語を改良して作られたC++という言語に影響を受けて作られたのがC#です[C]→[C++]→[C+++]という理屈に基づき、プラスマーク四つを右上、右下、左上、左下に並べると#に見えることから、C++++ = C#という名前になったと言われています。

12.3 特徴

構文はCや、C++、それとJavaなどの影響を受けています。オブジェクト指向と呼ばれる部類の言語なので、クラスの概念があります。Microsoft .NET Frameworkの中心言語であり、.NET Frameworkにおいて最も高い生産性を持つと言われています。UnityのスクリプトはC#で書く必要があります。Unityのようなゲーム製作にも向いている言語ということです。

12.4 実例

オブジェクト指向の代名詞とも言えるクラスによって、コードをスマートに記述できる。

ゲーム制作を例に挙げましょう。今、ゲームの中に「小石」や「棒」と言ったアイテムを作るとします。クラスを用いない場合は、StoneIDStickNameと言った変数でIDや名前を管理するでしょう。「剣」を追加するとなれば、SwordIDSwordNameなどの変数に加え、SwordAttackなどの関数も必要になります。これではどの変数がどのアイテムのものなのかが伝わりにくく、読みづらくて仕方ありません。

ここでクラスの出番です。クラスを使う一つ目の利点は、StoneNameStoneIDStone.Name Stone.IDのように纏める事ができることです。IDと名前をItemクラスに纏める事で、Itemをベースに作ったStoneStickからIDと名前にアクセスできるようになります。これなら変数も無闇に増えませんし、どのアイテムのIDなのかも一目でわかります。

二つ目の利点は、Itemクラスを拡張したものをアイテムとして扱える事です。Itemクラスを親とするWeaponクラスを作り、WeaponクラスにAttack関数(C#ではメソッドと呼びます)を定義します。WeaponクラスはItemクラスの特徴を自動で受け継いでいるので、WeaponクラスでもIDや名前を扱う事ができます。Weaponクラスを元にSwordを作れば、SwordからID、名前に加え、Attackメソッドを扱う事が出来ます。

ピストルやマシンガンといった銃火器も追加してみましょう。WeaponをベースにPistolMachineGunを作って... ですがWeaponクラスは剣や斧を想定したものなので、Weaponクラスをベースとする銃は殴ることしかできません。Weaponを書き換えるしかないのでしょうか。

そこでWeaponクラスをさらに拡張してみましょう。Weaponクラスを親とするGunクラスを作り、射程や弾速をRangeBulletSpeedというように定義します。Gun.Attackを遠隔攻撃に書き換えてしまいましょう。override Attackというように、overrideキーワードを使うことでAttack関数の挙動を乗っ取って、遠隔攻撃に書き換えてしまいます。親であるWeaponクラスには影響は及ばないので、安心して遠隔攻撃できます。

これでWeaponをベースに作ったSwordの挙動を変えることなく、Gunクラスをベースに作るPistolMachineGunを追加することができます。Itemクラスの要素であるPistol.ID等もちゃんと使えます。

アクセス修飾子、プロパティによってカプセル化ができる。

この機能は共同開発で役に立つものです。AさんとBさんによる共同開発を例にしましょう。AさんはWeaponに武器のリーチを示す変数と、リーチを設定するメソッドを作りました。このメソッドはリーチを負の値に設定できないようにするためのものでした。Bさんはそのメソッドの存在を知らず、武器のリーチを直接=で変更するコードを書きました。ここでBさんのコードに不備があり、武器のリーチが負の値に設定され、エラーが発生しました。

この事件の原因はリーチ変数がメソッドを介せずに変更できてしまうことです。C#(などの言語)にはこれを防ぐ仕組みとしてアクセス修飾子があります。クラス内で変数を宣言する際、前にprivateと記述することでクラス内からしかその値を扱えなくなります。この「クラス内」には継承先のクラスは含まれていません。継承先のクラスもその変数を扱えるようにするにはprotectedと記述します。リーチ変数を変更するメソッドを作り、このメソッド内でリーチを負の値に設定することができないように記述すればエラーを防ぐことができます。どこからでも自由にアクセスできるようにするにはpublicと記述します。

クラスが複雑になってくると、privateprotectedの数も増えてきます。この変数全てにsetID setName setReachとメソッドを書いていくのは手間がかかります。そこでC#(とVB)独自の機能、自動実装プロパティの出番です。変数の宣言の後に中括弧で、変数の値を変更するメソッドset(自動で引数valueが用意されます)と変数の値を取得するメソッドgetを書くことができます。

このset,get=で変数の値を変更する/取得する場合にも適用されます。リーチ変数のsetの中に負の値に設定できないようにすれば、=を用いて変数の値を負の値に指定しようとしても無視されるようになります。また、private set; public get;と書けば、値の変更はクラス内でのみ行え、値の取得は自由に行える「取得専用」の変数を作ることができます。

ガベージコレクションが優秀

C++で任意の長さの配列が欲しいときはnewキーワードを用います。また、不要になった配列は、deleteキーワードを使って明示的に破棄する必要があります。

対してC#には、C++のdeleteキーワードのようなものはありません。不要になった配列やクラスは、CPUが暇なときにまとめて破棄されます(ガベージコレクションと呼ばれます)。Pythonなどにも同じような機能がありますが、C#(とJava)のガベージコレクションは他の言語より優秀で、不要なものを確実に破棄できるといわれています。

明示的な破棄が必要なクラスもあるでしょう。C#はそのようなクラスの為に、usingステートメントというものを用意しています。usingステートメントを使って宣言されたクラスは、ステートメントの終了と同時に破棄されます。この機能を使えば、deleteを忘れた配列がメモリを圧迫するようなことはなくなります

多次元配列が高速

多次元配列は便利です。配列を入れ子状に宣言することで、書けるコードは大きく広がります。多くの言語の多次元配列は配列を配列にしてアクセスしています。多次元配列へのアクセスは、配列へのアクセスを次元数回繰り返す操作になります。100回程度のアクセスならどうでもいいですが、10^7以上になってくるとこの繰り返しが問題になってきます。

C#の多次元配列は、配列の配列ではありません。連続したメモリ領域として確保されます。これにより多次元配列へのアクセスは次元数の逆数倍に高速化されます。

LINQが最強

「配列にforを回して、中身が0に等しい要素の数を数える」「配列にforを回して、中身の要素を絶対値に書き換える」このような配列に対する成形、計測などの操作、頻繁に使いますよね。でも毎回for文を書くのは面倒...そこでC#の出番です。

この2つの操作はCount(v=>v==0)Select(v=>Math.Abs(v))で出来ます。別の配列を作ったりforでindexを気にする必要はありません。これがLanguage INtegrated Query、LINQの力です。

LINQにはこの2つの他にも様々な力を秘めています。条件を満たす要素の抽出や、重複要素の排除、条件を満たすはじめの要素の取得と、LINQに含まれるメソッドの数は50を超えます。LINQを使いこなすことで、C#のコードはより読みやすく、短くなるのです。

12.5 終わりに

C#には便利な機能が枚挙に暇がないほどあります。ここではその中でも特に便利な5つに絞って紹介しました。この部誌を読んで少しでも「C#って便利そうだな」と感じていただけたら幸いです。