ブルーノのC#プログラミング & unity勉強日記

プログラミング素人、ブルーノの自主勉強ノートです。他のプログラミングを勉強したい方の助けになれば幸いです。その他趣味の雑記もしていきたいです

例外について(1/3)

f:id:covory10101101276:20171206170757p:plain

みなさんこんにちは🌚

お昼ご飯をついつい買い込んでしまうブルーノです。ポケ森をやって空腹を忘れさせています😑

さて今回からは例外についてまとめていきます。

 

例外について

コンパイルが正常にできたプログラムなどにおいてもエラーは度々発生します。例えば境界の範囲以上に配列にアクセスしようとしたり、Parseメソッドなどで文字列型を数値に変換しようとしてしまった場合などがそうです。こういった予期せぬエラーを例外(Exeption)と言います。例外が発生するとその例外を表す例外オブジェクトが自動的に生成され、プログラムに送られてきます。これを「例外がスローされる」と言います。このスローは英語でthrowのことで「投げる」という意味ですね。文字通り例外が投げられるということです。まずは簡単な例を作ってみましょう

f:id:covory10101101276:20171206172357p:plain

f:id:covory10101101276:20171206172401p:plain

見ればわかるように、ユーザーから二つの数を受け取り、引き算をしてその結果を表示する簡単なプログラムです。問題はこの9行目と13行目で、ここでもしstr1,2に文字列が入っていてdouble型に変換できなかったらどうなるでしょうか

f:id:covory10101101276:20171206172653p:plain

f:id:covory10101101276:20171206172657p:plain

私の場合はこのようにスローされましたと表示されました。windowsアプリケーションの場合は強制終了させられるかもしれません。どこかでうっかりミスをしただけでいちいちプログラムを強制終了されたんじゃたまったものじゃないですね。C#ではこれに対応できるように処置が用意されています。

まず、例外が起こりそうな文をtryブロックの中に記述します。そしてそのtryボックスの中の記述通りのことが起こった場合に実行されるcatchブロックを記述します。具体的には以下の通りです。

f:id:covory10101101276:20171206174143p:plain

f:id:covory10101101276:20171206174150p:plain

まず先ほどと違う点として、例外が投げられそうな記述をtryブロックの中に書き込んでいます。そしてそこで例外が発生した時にcatchブロックの中の処理を行なっています。double d1, d2には例外が投げられた時に何も入っていない状態になってしまうために0で初期化しています。つまり

例外が発生しそうな記述をtryブロックで囲む

起こった場合の処理をすぐ下のcatchブロックに記述する

そのまま下へ実行されていく

という流れになります。

さて、例外が起こったらそれへの対応をすることには成功しましたがこのプログラムでは例外の種類には触れていませんでした。 その内容に応じて対応を変えられればより便利そうですね

例えば...

  • 「年齢を入力して下さい」→「二十」

→「数字で入力して下さい」

  • 「年齢を入力して下さい」→「20」

→「半角で入力して下さい」

など 

まあこの場合は開発者が予想できているので変換してやれよという気もしますが笑

さて、実は例外が投げられると先ほどは言いましたが、これは実はSystem名前空間で定義されているExceptionクラスとそこから派生したクラスからなる「例外オブジェクト」というものが生成されプログラムに送られてくるという行程のことを言っていたのです。この投げられた例外オブジェクトは種類によってその中身(メンバ)が様々に派生しています。このメンバによって対応を変えるようcatchブロックの中に色々なケースの対応を書いておけば良いわけです。

f:id:covory10101101276:20171206181540p:plain

f:id:covory10101101276:20171206181544p:plain

3つのcacthブロックの中にそれぞれ例外クラスについての対応を書きました。それぞれの引数の中の記述の説明は以下の通りです。

  • IndexOutOfRangeExceptionクラス:Exceptionクラスの派生クラス。配列の境界を超えてアクセスしようとすると投げられる例外
  • DivideByZeroExceptionクラス:Exceptionクラスの派生クラス。0で割ろうとした時に投げられる例外
  • Exceptionクラス:全ての例外クラスの基本クラス

結果を見ればわかるようにメインメソッド内で0で割ろうとしたために真ん中のDivideByZeroExceptionクラスがキャッチされました。そして注目すべきは3つ目のExceptionクラス。全ての例外クラスを包括している基本クラスなのですが、これはキャッチされていません。これは、手前で先に別のキャッチ節でキャッチされているのでもうこの一連のキャッチ節では捕まらないからです。これは重要なことですね。ではDivideByZeroExceptionとExceptionのキャッチブロックを逆にするとどうなるかというと実はコンパイルエラーになります。全ての例外はExceptionにキャッチされるのは明らかなのでその後のcatch説が意味を持たなくなってしまうためです。

今回はここまでにしておきます。

 

例外は記述する量が膨大になりそうですがきちんとケアをすることで異常が起きないプログラムが組めそうです。いざとなればExceptionクラスで指定すればいいからヘーキヘーキ(棒

デリゲート/イベントの復習・応用

f:id:covory10101101276:20171205185835p:plain

みなさんこんにちは🌚

上の画像、マリーナ・ベイというシンガポールの高級ホテルらしいんですがなんか屋上に船が刺さってるみたいですね。FF7のゴールドソーサーを思い出しました(笑)

さて今回はデリゲートの総まとめということでちょっとした一桁限定の加算プログラムを組んで見たいと思います。キーボードから数字が入力されるとその値を足していき、cキーを押すと合計をクリア、xキーでプログラムを終了する、といったものです。早速まずはプログラムを書き、紐解いていくことにしましょう

f:id:covory10101101276:20171205193229p:plain

f:id:covory10101101276:20171205193243p:plain

f:id:covory10101101276:20171205193250p:plain

3つのクラスがこのプログラムにはあります。

Bruno079 →イベントを発生させるクラス

Bruno080 →イベント発生時に呼び出される、つまり起こるプログラム

Bruno081 →これらを準備し、実際に行うプログラム(入力されたキーが終了かどうかはここで判別する)

 

こう書くと単純に見えますね。Bruno081クラスには見慣れないキーワードがいくつもあるので少し混乱してしまいますが。ではメインメソッドの中身に沿って説明していきます。

  • 43行目:ユーザーへの説明
  • 44行目:ConsoleKeyInfo構造体は押されたキーを記述(情報を取得と同義?)します。これを定義。
  • 46,47行目:イベントを実行するクラスとイベントの内容をインスタンス化。
  • 49行目:イベントフィールドにイベントハンドラを設定。

ここまでが準備ですね。そしてwhileループの中身です。

  • 53行目:if(Console.KeyAvailable)というのはキーが押されている場合という意味です。押されていないとき(KeyAvailableがfalseの時)は何も起こりません。
  • 55行目:押されたキーの情報をReadKeyメソッドで取得します。この引数のtrueというのは入力された情報を表示しないという意味です。そして取得した情報はcki構造体に送られます。
  • 56~60行目:cki構造体に送られた文字がxの場合プログラムを終了します。
  • 62行目:ようやくここまで通過したキーの情報をConsoleKeyInfo構造体のKeyCharプロパティにより一桁のunicode文字を49行目のHandlerデリゲートを通してイベントフィールドに返します。

と、こうなります。めっちゃ長かったですね〜😩😂でもおかげでメインメソッドはとてもスッキリしましたね!!デリゲートをもし使わなかったらこのクラスの内容がややこしく膨大なものになっていたでしょう。今回はここまでにしておきます。

 

このブログを書いていると時間があっという間に経ってしまいますがとても楽しいです。今回やったのなんてまさにゲーム開発の基礎っぽいですよね。早く開発して見たいなあ

 

イベントについて

f:id:covory10101101276:20171205170218p:plain

みなさんこんにちは🌚

ポケ森でもぐもぐの元不足に悩まされているブルーノです。ツバクロをキャンプから追い出してお礼をせしめないと...

さて今回はGUIベースのアプリケーションには必須なイベントというものについてやっていきたいと思います。

 

イベント

今までスクリーンショットで貼ってきたものはコンソールアプリケーション(CUI)と呼ばれるもので、ユーザーからの入力に反応する場合(例えばConsole.ReadLineなど)、キーボードからの入力についてのみ反応するようにプログラムを組んでいました。もちろんこれだけでも文字の型を適切なものにしたり時には弾いたりなど、あらゆる入力に対応できるよう工夫が必要でしたが、これが一般的にみるグラフィカルユーザーインターフェースベースのアプリの場合ユーザーはどこをクリック(タップ)したり、ドラッグしたり、時にはキーを打ち込んだり、まあやることが多すぎてわかりません。そこで今まではプロパティなどで「入力されたものが何々(以外)だったら」という形でしたが、今度は「何々(以外)が入力されたら」→「何々する」という形にしていきたいと思います。この「何かが起きた」ことをイベントと言い、このイベントが起きてからそれに対する一連の動作の流れをイベントハンドラと言います。

では画像を見ながら少しづつ紐解いていきたいと思います。

f:id:covory10101101276:20171205174343p:plain

f:id:covory10101101276:20171205174347p:plain

まず注目するのが5~14行目のBruno075クラスで、これはイベントを発生させるクラスになります。7行目のeventキーワードを使ったものをイベントフィールドと言い、これをメインメソッドで実行させます。しかし7行目時点ではこのイベントフィールドには何も入っていないので実行させてはいけません。この何もない状態をnull(ヌル)と言います。そこで9行目~13行目のOnEventnameメソッドでeventnameがnullでない(何か入っている)時にこれを呼び出せるスイッチを設けています。実際のメインメソッド(43行目)ではこのスイッチを実行していますね。このスイッチの役割を果たすメソッドの名前は一般的に「On~~」という名前にします(もちろんしなくても構いません)。Bruno076, 077クラスはただ2種類のshowを表示するだけのメソッドです。これをBruno078クラスのメインメソッドでまず36,37行目にあるようにインスタンス化します。そしてイベントを発生させるクラスもインスタンス化し、40,41行目にあるようにその中のイベントフィールドにメソッドを追加していきます。(この時ソフトに「冗長なデリゲート宣言」とか言われたんですが無駄に長いってことですかね😅もっと短くできるのかな)

そして最後に格納したメソッドを43行目のOnEventnameメソッドで実行しています。

イベントフィールドにメソッドを追加するときは「=」ではなく「+=」で行うよう注意しましょう

今回はここまでにして起きます。

 

だんだん説明が長くなってきちゃいました。でもこれら全部大事なことなので、ノートに書き込む感覚でしっかりメモして行こうと思います。

ポケ森楽しい〜〜。もぐもぐのもとは相変わらず足りない😭

匿名メソッドとラムダ式について

f:id:covory10101101276:20171205141445p:plain

みなさんこんにちは🌚

昨日朝ごはんを食べた瞬間に胸が苦しくなって病院に担ぎ込まれたブルーノです。結局原因は不明だそうですがいまだに深く息を吸い込むと胸が痛くなります。肋間神経痛かもしれません。まあしばらくご飯はゆっくり食べる事にします😅さて今回は匿名メソッドとラムダ式というものについてまとめていきます

 

匿名メソッド

前回はすでにあるメソッドをデリゲートを通して実行し、いちいちインスタンス化→実行という手間をかけない方法についてやりましたが、今度の匿名メソッドはメソッドをあらかじめ定義しておく必要も無くなってしまいます。では下の図を見てください

f:id:covory10101101276:20171205145411p:plain

f:id:covory10101101276:20171205145416p:plain

7~11行目のShowメソッドは入力された文字列をそのまま返すシンプルなものです。22行目でこのメソッドのデリゲートを作成し、次の行で呼び出しています。ここまでは従来のデリゲートと同じです。その次の25行目で少し従来のものと違った宣言の仕方をしているものがありますね。

MyDelegate b = delegate(引数) { ... }

従来のデリゲートと比較してみましょう

delegate b = new Mydelegate(引数)

デリゲート名(赤字)デリゲートの宣言(青字)が逆になっているほか、匿名メソッドは後ろに{ ... } とありますね。実はここにメソッドの中身を書き込むようになっていて、デリゲートの宣言と中身をここでいっぺんにできてしまうのです。つまり、メソッドの名前を書き込まずにデリゲートの宣言だけでメソッドを作ることができるので、匿名のメソッドというわけですね!実行結果は見て分かるように両者に差はありません。では次に、この匿名メソッドをさらに簡略化できてしまうラムダ式についてまとめます。

 

ラムダ式

先ほどの匿名メソッドの他にデリゲートを簡略化する方法として、ラムダ式というものが存在します。まずは下の画像を見てください。

f:id:covory10101101276:20171205161342p:plain

f:id:covory10101101276:20171205161347p:plain

メインメソッドの中の14行目が通常の呼び出し、16~17行目がラムダ式による呼び出しになっています。ラムダ式の呼び出し方は以下のようになっていますね

MyDelegate b = () => { ...; };

この{ ... }のなかで呼び出すメソッドを指定しています。この => という矢印みたいなものをラムダ演算子と言います。矢印の手前の()にはデリゲートへの引数が入ります。今回は引数は指定していないので空白ですね。また、{ ... }のなかに

{ Console.WriteLine("..."); }

のように直接メソッドの内容を書き込むこともできます。こうするとまるで匿名メソッドのようですね。さっきの4行程の匿名メソッドの記入がラムダ式なら1行で終わってしまいました。こっちの方が楽ですよね。実際C#の開発者の方も「ラムダ式が先に導入されていれば匿名メソッドはいらなかった」と発言しているそうです(笑)。

また、マルチキャストデリゲーションについては以下の通りです。

f:id:covory10101101276:20171205163244p:plain

f:id:covory10101101276:20171205163252p:plain

今回はここまでにしておきます。

ラムダ式があれば簡単なメソッドならいちいち定義せずに実行できてしまいそうですね。まあデリゲートの引数やデータ型の関係で似たようなメソッドしか定義できませんが便利そうです。今度は色々なunityゲームのオープンソースとかも見てみたいなぁ

デリゲート

f:id:covory10101101276:20171113164700j:image

みなさんこんにちは🌚

貧乏生活で身も心も細っていくブルーノです。バイトやめたら一気にお金なくなりました(T . T)習慣付いた浪費グセってこわい😭

さて今回からはデリゲートについてまとめて行きたいと思います

 

デリゲートについて

デリゲート(delegate)は英語で委任するという意味です。プログラミングにおいてはデータ型とパラメータリストを指定したデリゲートを宣言することでメソッドを代行してもらうことができます。どういうことか、何に使えるのかちょっと見てみます

 f:id:covory10101101276:20171113165828p:imagef:id:covory10101101276:20171113165830p:image

デリゲートはクラス外で宣言しておいて16行目のようにインスタンス化する際にメソッドの名前を入力することでデリゲート名でそのメソッドを呼び出すことができるようになるんですね。結果はShowメソッドが2回呼び出されていますね。これはたまたま呼び出されるメソッドと呼び出すクラスが同じでした。今度は別のクラスで呼び出してみましょう。

f:id:covory10101101276:20171201112724p:imagef:id:covory10101101276:20171201112725p:image

注目するのは20行目で、デリゲートにクラスとその中のメソッドへの参照を入れています。

 

マルチキャストデリゲーションについて

まずはこちらのコードを見てください。

f:id:covory10101101276:20171201115037p:imagef:id:covory10101101276:20171201115039p:image

24行目でBruno069クラス内の高らかな笑い声のメソッドをデリゲートに当てて次の行で呼び出しています。そして27行目で今度はアヒルの鳴き声のメソッドを同じインスタンスに入れて呼び出しています。これを見ると一つのデリゲートに委託できるメソッドは一つだけなのでしょうか。いえいえ、実は呼び出すメソッドを追加することができるのです。この24行目の後に

m += new MyDelegate(b.show2);

とすることで、このデリゲートを呼び出した際ネズミとアヒルの両方の鳴き声を聞くことができるのです。逆にこの後に

m -= new MyDelegate(b.show1);

とすればアヒルの鳴き声だけになります。このように呼び出すメソッドをいくつも増やしたりすることをマルチキャストデリゲーションと言います。声に出して言いたいですね!

 

デリゲートの基本を説明したところで今回は終わります。

冬の大会でこの二週間忙しかったあ〜〜🤯🤯🤯

久しぶりにこの記事書くと楽しいです😊

もう12月ですね。このブログも半年続いたお知らせが来ましたがのんびりペースすぎますね...

もっと頑張ろうっと

 

DateTime構造体

f:id:covory10101101276:20171108130129j:image

みなさんこんにちは🌚

寒くなってきて長袖が必要になって来ましたがタンスの中を見てみると1着しか長袖がなかったブルーノです。また最近サボりがちになっていましたが更新していきたいと思います。今回は構造体の中でも便利なDateTime構造体についてです。

 

DateTime構造体について

 C#にもともと用意されている構造体にDateTime構造体というものがあります。この構造体の中でもNowプロパティはとても便利で、現在の日付・時刻を年からミリ秒まで取得することができるのです。直接メモリにアクセスする値型にはこのようなあらかじめ備わっている機能もあるのですね。ちょっと使ってみます。

f:id:covory10101101276:20171108211236p:plain

f:id:covory10101101276:20171108211241p:plain

アプリを作る際なんかに大いに役立ちそうですね。

今回はこれで終わると同時に構造体についても終わります。次回からはデリゲートとイベントというものについてやっていきます。

 

夜と朝が寒くなってきて朝の早起きが大変になってきました。日課の早朝ランニングも最近はやっていないし、誰か俺を律してくれえ〜〜😭

値渡しと参照渡しの違いについて

f:id:covory10101101276:20171108190139j:plainみなさんこんにちは🌚

値渡しと参照渡しの違いがわからず、また値型と参照型を混同してしまって最近更新が遅れてしまっていたブルーノです。様々なサイトを駆けずり回ってようやく理解できたきがするのでここにノートとしてまとめておきます!

 

メソッドに値を加工してもらいたい時はメソッドのブランケット「()」にパラメータ(引数)を渡し、それを加工するのですがなんと渡すものやその方法によって結果が異なってくるのです。その違いが値渡しと参照渡しになります。

値渡しについて

この二つの名前のせいで翻弄され続けていましたがズバリ値渡しは、その値のコピーを渡すことです。主にint型やlong型などのプリミティブ型と呼ばれる関数を引数に渡す場合この値渡しになります。最初の方にやった「変数について」

変数について - ブルーノのC#プログラミング & unity勉強日記

という記事でも値型と参照型というキーワードが出てきましたがこれらデータ型とは別のものであり、値型だからと言って値渡しになるとは限らず、参照型の変数だからと言って参照渡しになるとは限らないのです。この重要な事項が関わってくるのがstring型で、これはデータ型は参照型ですが値渡しになるのです。良く使う型であるだけに注意が必要ですね。では何が値型になるのかというと、なんの補助もなくそのまま使う場合はオブジェクト以外のものがこの値渡しになります。

f:id:covory10101101276:20171108200146p:plain

f:id:covory10101101276:20171108200150p:plain

上の画像にあるようにint a = 6と宣言してint型の変数を一つ用意し、Ichitasuメソッドで1足してその値を返していますが結果は変わらず6のままです。これはIchitasuメソッドに渡された6とint aに格納されている6は別物だからです。Ichitasuメソッドに渡されたのはint aの値のコピーであり、要は13行めでIchitasu(6)と書いているも同然なのです。

オブジェクト以外って具体的になんだよと言いたくなると思いますが次の参照渡しでオブジェクトをまとめるのでそれ以外と覚えてください。

 

参照渡しについて

では参照渡しとはなんなのか、オブジェクトをメソッドに渡す際はこの参照渡しになるのですが、参照渡しはオブジェクトそのものを加工してもらいます。

f:id:covory10101101276:20171108202900p:plain

f:id:covory10101101276:20171108202904p:plain

 

12行めではint aしか書かれていないBruno063クラスをオブジェクト化しています。そしてBruno063クラスを加工するIchitasuメソッドが13~16行めに記述されています。このそして17行めでこのIchitasuメソッドに渡されたBruno063 b は加工されます。これはコピーではなく現物で行われます。つまり、クラスからオブジェクト化されたものは加工できるということになります。ですが同じクラス内でメソッドに渡して加工したい時もありますよね。いちいちオブジェクト化しなければならないのは面倒だ...そこで使えるのがref, outキーワードなんですね。refキーワードをつけた引数は参照渡しになるため、メソッドに渡されるのはコピーではなくそのものになるのです。

 

最後に

オブジェクトは参照渡しになるのでクラスから作られる=参照渡しと捉えて良いですが構造体の場合は値型でしたね。構造体も使いたい場合はstruct sのようにクラスのオブジェクト化の時と似た感じで使いますが構造体は値型であるため、メソッドに渡す際はrefキーワードをつけて参照呼び出しにする必要があります。この部分がこの一週間わからず悩んでいたところです。スッキリしたところで今回は終わります。

 

あー早くunityの方に取り掛かってアプリ開発にも着手しないともう時間がない...もう今の知識だけでスクリプト面は大丈夫なのだろうか....