74回生 cobalt
こんにちは、cobaltです。私はC#というプログラミング言語が大好きなので、C#について書いていこうと思います
プログラミング言語とは、コンピューター(この場合はスマートフォンなんかも含みます)に命令するために作られた人工言語です。長い歴史(70年ほど)と多くの種類があり、コンピューターの扱う2進数に近いものや、人間の扱う言葉に近いもの、3種類の言葉しか使わないものなど色々な種類があります。
C#は、アンダース・ヘルスバーグというプログラマが設計した言語で、Cという言語を改良して作られたC++という言語に影響を受けて作られたのがC#です[C]→[C++]→[C+++]という理屈に基づき、プラスマーク四つを右上、右下、左上、左下に並べると#に見えることから、C++++ = C#という名前になったと言われています。
構文はCや、C++、それとJavaなどの影響を受けています。オブジェクト指向と呼ばれる部類の言語なので、クラスの概念があります。Microsoft .NET Frameworkの中心言語であり、.NET Frameworkにおいて最も高い生産性を持つと言われています。UnityのスクリプトはC#で書く必要があります。Unityのようなゲーム製作にも向いている言語ということです。
ゲーム制作を例に挙げましょう。今、ゲームの中に「小石」や「棒」と言ったアイテムを作るとします。クラスを用いない場合は、StoneID
、StickName
と言った変数でIDや名前を管理するでしょう。「剣」を追加するとなれば、SwordID
やSwordName
などの変数に加え、SwordAttack
などの関数も必要になります。これではどの変数がどのアイテムのものなのかが伝わりにくく、読みづらくて仕方ありません。
ここでクラスの出番です。クラスを使う一つ目の利点は、StoneName
やStoneID
をStone.Name
Stone.ID
のように纏める事ができることです。IDと名前をItem
クラスに纏める事で、Itemをベースに作ったStone
やStick
からIDと名前にアクセスできるようになります。これなら変数も無闇に増えませんし、どのアイテムのIDなのかも一目でわかります。
二つ目の利点は、Item
クラスを拡張したものをアイテムとして扱える事です。Item
クラスを親とするWeapon
クラスを作り、Weapon
クラスにAttack
関数(C#ではメソッドと呼びます)を定義します。Weapon
クラスはItem
クラスの特徴を自動で受け継いでいるので、Weapon
クラスでもIDや名前を扱う事ができます。Weapon
クラスを元にSword
を作れば、Sword
からID、名前に加え、Attack
メソッドを扱う事が出来ます。
ピストルやマシンガンといった銃火器も追加してみましょう。Weapon
をベースにPistol
とMachineGun
を作って... ですがWeapon
クラスは剣や斧を想定したものなので、Weapon
クラスをベースとする銃は殴ることしかできません。Weapon
を書き換えるしかないのでしょうか。
そこでWeapon
クラスをさらに拡張してみましょう。Weapon
クラスを親とするGun
クラスを作り、射程や弾速をRange
、BulletSpeed
というように定義します。Gun.Attack
を遠隔攻撃に書き換えてしまいましょう。override Attack
というように、override
キーワードを使うことでAttack
関数の挙動を乗っ取って、遠隔攻撃に書き換えてしまいます。親であるWeapon
クラスには影響は及ばないので、安心して遠隔攻撃できます。
これでWeapon
をベースに作ったSword
の挙動を変えることなく、Gun
クラスをベースに作るPistol
やMachineGun
を追加することができます。Item
クラスの要素であるPistol.ID
等もちゃんと使えます。
この機能は共同開発で役に立つものです。AさんとBさんによる共同開発を例にしましょう。AさんはWeapon
に武器のリーチを示す変数と、リーチを設定するメソッドを作りました。このメソッドはリーチを負の値に設定できないようにするためのものでした。Bさんはそのメソッドの存在を知らず、武器のリーチを直接=
で変更するコードを書きました。ここでBさんのコードに不備があり、武器のリーチが負の値に設定され、エラーが発生しました。
この事件の原因はリーチ変数がメソッドを介せずに変更できてしまうことです。C#(などの言語)にはこれを防ぐ仕組みとしてアクセス修飾子があります。クラス内で変数を宣言する際、前にprivate
と記述することでクラス内からしかその値を扱えなくなります。この「クラス内」には継承先のクラスは含まれていません。継承先のクラスもその変数を扱えるようにするにはprotected
と記述します。リーチ変数を変更するメソッドを作り、このメソッド内でリーチを負の値に設定することができないように記述すればエラーを防ぐことができます。どこからでも自由にアクセスできるようにするにはpublic
と記述します。
クラスが複雑になってくると、private
やprotected
の数も増えてきます。この変数全てに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#の多次元配列は、配列の配列ではありません。連続したメモリ領域として確保されます。これにより多次元配列へのアクセスは次元数の逆数倍に高速化されます。
「配列に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#のコードはより読みやすく、短くなるのです。
C#には便利な機能が枚挙に暇がないほどあります。ここではその中でも特に便利な5つに絞って紹介しました。この部誌を読んで少しでも「C#って便利そうだな」と感じていただけたら幸いです。