例外について(2/3)
みなさんこんにちは🌚
ちょっとゼルダの伝説の時のオカリナに夢中になっていて気づけば最後の記事から2週間が経ってしまっていました。。。ゲームの面白さは一概にグラフィックや派手な展開だけではないということを痛感しました😄
さて今回は前回に引き続き例外の処理についてまとめていきます。
Finally節
前回からtry節、catch節と続いてまた新しい節であるFinally節を今回は紹介します。try節で例外が起こった時catch節に行くのは前回やりましたが、この時catch節でこのメソッドが終了させられたり、別の場所に飛ばされたりする場合、それ以降の記述は本来適用されません。しかし中にはcatch節の内容を実行してもしなくてもどうしても実行したい文などが出て来る場合もあり、その時にこのFinally節を設けておくと、try節の後に絶対に実行してくれます。調べたところアプリケーション自体を終了しない限りは実行されるようです。では実際に例を見てみましょう。
各例外をキャッチした後に必ず続けるかどうかをwhileループの中で聞いています。このFinally節にのみループを抜ける手段が設けられるので絶対に来て欲しいですよね。今回はとりあえずここまでにします。
気づけば断捨離で長袖をほとんど捨ててしまっていたためにとても寒い思いをしています🤮図書館に避難してこのブログの方にまた注力していきたいです!
学校も今週までだ!冬休みは勉強するぞー
例外について(1/3)
みなさんこんにちは🌚
お昼ご飯をついつい買い込んでしまうブルーノです。ポケ森をやって空腹を忘れさせています😑
さて今回からは例外についてまとめていきます。
例外について
コンパイルが正常にできたプログラムなどにおいてもエラーは度々発生します。例えば境界の範囲以上に配列にアクセスしようとしたり、Parseメソッドなどで文字列型を数値に変換しようとしてしまった場合などがそうです。こういった予期せぬエラーを例外(Exeption)と言います。例外が発生するとその例外を表す例外オブジェクトが自動的に生成され、プログラムに送られてきます。これを「例外がスローされる」と言います。このスローは英語でthrowのことで「投げる」という意味ですね。文字通り例外が投げられるということです。まずは簡単な例を作ってみましょう
見ればわかるように、ユーザーから二つの数を受け取り、引き算をしてその結果を表示する簡単なプログラムです。問題はこの9行目と13行目で、ここでもしstr1,2に文字列が入っていてdouble型に変換できなかったらどうなるでしょうか
私の場合はこのようにスローされましたと表示されました。windowsアプリケーションの場合は強制終了させられるかもしれません。どこかでうっかりミスをしただけでいちいちプログラムを強制終了されたんじゃたまったものじゃないですね。C#ではこれに対応できるように処置が用意されています。
まず、例外が起こりそうな文をtryブロックの中に記述します。そしてそのtryボックスの中の記述通りのことが起こった場合に実行されるcatchブロックを記述します。具体的には以下の通りです。
まず先ほどと違う点として、例外が投げられそうな記述をtryブロックの中に書き込んでいます。そしてそこで例外が発生した時にcatchブロックの中の処理を行なっています。double d1, d2には例外が投げられた時に何も入っていない状態になってしまうために0で初期化しています。つまり
例外が発生しそうな記述をtryブロックで囲む
↓
起こった場合の処理をすぐ下のcatchブロックに記述する
↓
そのまま下へ実行されていく
という流れになります。
さて、例外が起こったらそれへの対応をすることには成功しましたがこのプログラムでは例外の種類には触れていませんでした。 その内容に応じて対応を変えられればより便利そうですね
例えば...
- 「年齢を入力して下さい」→「二十」
→「数字で入力して下さい」
- 「年齢を入力して下さい」→「20」
→「半角で入力して下さい」
など
まあこの場合は開発者が予想できているので変換してやれよという気もしますが笑
さて、実は例外が投げられると先ほどは言いましたが、これは実はSystem名前空間で定義されているExceptionクラスとそこから派生したクラスからなる「例外オブジェクト」というものが生成されプログラムに送られてくるという行程のことを言っていたのです。この投げられた例外オブジェクトは種類によってその中身(メンバ)が様々に派生しています。このメンバによって対応を変えるようcatchブロックの中に色々なケースの対応を書いておけば良いわけです。
3つのcacthブロックの中にそれぞれ例外クラスについての対応を書きました。それぞれの引数の中の記述の説明は以下の通りです。
- IndexOutOfRangeExceptionクラス:Exceptionクラスの派生クラス。配列の境界を超えてアクセスしようとすると投げられる例外
- DivideByZeroExceptionクラス:Exceptionクラスの派生クラス。0で割ろうとした時に投げられる例外
- Exceptionクラス:全ての例外クラスの基本クラス
結果を見ればわかるようにメインメソッド内で0で割ろうとしたために真ん中のDivideByZeroExceptionクラスがキャッチされました。そして注目すべきは3つ目のExceptionクラス。全ての例外クラスを包括している基本クラスなのですが、これはキャッチされていません。これは、手前で先に別のキャッチ節でキャッチされているのでもうこの一連のキャッチ節では捕まらないからです。これは重要なことですね。ではDivideByZeroExceptionとExceptionのキャッチブロックを逆にするとどうなるかというと実はコンパイルエラーになります。全ての例外はExceptionにキャッチされるのは明らかなのでその後のcatch説が意味を持たなくなってしまうためです。
今回はここまでにしておきます。
例外は記述する量が膨大になりそうですがきちんとケアをすることで異常が起きないプログラムが組めそうです。いざとなればExceptionクラスで指定すればいいからヘーキヘーキ(棒
デリゲート/イベントの復習・応用
みなさんこんにちは🌚
上の画像、マリーナ・ベイというシンガポールの高級ホテルらしいんですがなんか屋上に船が刺さってるみたいですね。FF7のゴールドソーサーを思い出しました(笑)
さて今回はデリゲートの総まとめということでちょっとした一桁限定の加算プログラムを組んで見たいと思います。キーボードから数字が入力されるとその値を足していき、cキーを押すと合計をクリア、xキーでプログラムを終了する、といったものです。早速まずはプログラムを書き、紐解いていくことにしましょう
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デリゲートを通してイベントフィールドに返します。
と、こうなります。めっちゃ長かったですね〜😩😂でもおかげでメインメソッドはとてもスッキリしましたね!!デリゲートをもし使わなかったらこのクラスの内容がややこしく膨大なものになっていたでしょう。今回はここまでにしておきます。
このブログを書いていると時間があっという間に経ってしまいますがとても楽しいです。今回やったのなんてまさにゲーム開発の基礎っぽいですよね。早く開発して見たいなあ
イベントについて
みなさんこんにちは🌚
ポケ森でもぐもぐの元不足に悩まされているブルーノです。ツバクロをキャンプから追い出してお礼をせしめないと...
さて今回はGUIベースのアプリケーションには必須なイベントというものについてやっていきたいと思います。
イベント
今までスクリーンショットで貼ってきたものはコンソールアプリケーション(CUI)と呼ばれるもので、ユーザーからの入力に反応する場合(例えばConsole.ReadLineなど)、キーボードからの入力についてのみ反応するようにプログラムを組んでいました。もちろんこれだけでも文字の型を適切なものにしたり時には弾いたりなど、あらゆる入力に対応できるよう工夫が必要でしたが、これが一般的にみるグラフィカルユーザーインターフェースベースのアプリの場合ユーザーはどこをクリック(タップ)したり、ドラッグしたり、時にはキーを打ち込んだり、まあやることが多すぎてわかりません。そこで今まではプロパティなどで「入力されたものが何々(以外)だったら」という形でしたが、今度は「何々(以外)が入力されたら」→「何々する」という形にしていきたいと思います。この「何かが起きた」ことをイベントと言い、このイベントが起きてからそれに対する一連の動作の流れをイベントハンドラと言います。
では画像を見ながら少しづつ紐解いていきたいと思います。
まず注目するのが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メソッドで実行しています。
イベントフィールドにメソッドを追加するときは「=」ではなく「+=」で行うよう注意しましょう
今回はここまでにして起きます。
だんだん説明が長くなってきちゃいました。でもこれら全部大事なことなので、ノートに書き込む感覚でしっかりメモして行こうと思います。
ポケ森楽しい〜〜。もぐもぐのもとは相変わらず足りない😭
匿名メソッドとラムダ式について
みなさんこんにちは🌚
昨日朝ごはんを食べた瞬間に胸が苦しくなって病院に担ぎ込まれたブルーノです。結局原因は不明だそうですがいまだに深く息を吸い込むと胸が痛くなります。肋間神経痛かもしれません。まあしばらくご飯はゆっくり食べる事にします😅さて今回は匿名メソッドとラムダ式というものについてまとめていきます
匿名メソッド
前回はすでにあるメソッドをデリゲートを通して実行し、いちいちインスタンス化→実行という手間をかけない方法についてやりましたが、今度の匿名メソッドはメソッドをあらかじめ定義しておく必要も無くなってしまいます。では下の図を見てください
7~11行目のShowメソッドは入力された文字列をそのまま返すシンプルなものです。22行目でこのメソッドのデリゲートを作成し、次の行で呼び出しています。ここまでは従来のデリゲートと同じです。その次の25行目で少し従来のものと違った宣言の仕方をしているものがありますね。
MyDelegate b = delegate(引数) { ... }
従来のデリゲートと比較してみましょう
delegate b = new Mydelegate(引数)
デリゲート名(赤字)とデリゲートの宣言(青字)が逆になっているほか、匿名メソッドは後ろに{ ... } とありますね。実はここにメソッドの中身を書き込むようになっていて、デリゲートの宣言と中身をここでいっぺんにできてしまうのです。つまり、メソッドの名前を書き込まずにデリゲートの宣言だけでメソッドを作ることができるので、匿名のメソッドというわけですね!実行結果は見て分かるように両者に差はありません。では次に、この匿名メソッドをさらに簡略化できてしまうラムダ式についてまとめます。
先ほどの匿名メソッドの他にデリゲートを簡略化する方法として、ラムダ式というものが存在します。まずは下の画像を見てください。
メインメソッドの中の14行目が通常の呼び出し、16~17行目がラムダ式による呼び出しになっています。ラムダ式の呼び出し方は以下のようになっていますね
MyDelegate b = () => { ...; };
この{ ... }のなかで呼び出すメソッドを指定しています。この => という矢印みたいなものをラムダ演算子と言います。矢印の手前の()にはデリゲートへの引数が入ります。今回は引数は指定していないので空白ですね。また、{ ... }のなかに
{ Console.WriteLine("..."); }
のように直接メソッドの内容を書き込むこともできます。こうするとまるで匿名メソッドのようですね。さっきの4行程の匿名メソッドの記入がラムダ式なら1行で終わってしまいました。こっちの方が楽ですよね。実際C#の開発者の方も「ラムダ式が先に導入されていれば匿名メソッドはいらなかった」と発言しているそうです(笑)。
また、マルチキャストデリゲーションについては以下の通りです。
今回はここまでにしておきます。
ラムダ式があれば簡単なメソッドならいちいち定義せずに実行できてしまいそうですね。まあデリゲートの引数やデータ型の関係で似たようなメソッドしか定義できませんが便利そうです。今度は色々なunityゲームのオープンソースとかも見てみたいなぁ
デリゲート
みなさんこんにちは🌚
貧乏生活で身も心も細っていくブルーノです。バイトやめたら一気にお金なくなりました(T . T)習慣付いた浪費グセってこわい😭
さて今回からはデリゲートについてまとめて行きたいと思います
デリゲートについて
デリゲート(delegate)は英語で委任するという意味です。プログラミングにおいてはデータ型とパラメータリストを指定したデリゲートを宣言することでメソッドを代行してもらうことができます。どういうことか、何に使えるのかちょっと見てみます
デリゲートはクラス外で宣言しておいて16行目のようにインスタンス化する際にメソッドの名前を入力することでデリゲート名でそのメソッドを呼び出すことができるようになるんですね。結果はShowメソッドが2回呼び出されていますね。これはたまたま呼び出されるメソッドと呼び出すクラスが同じでした。今度は別のクラスで呼び出してみましょう。
注目するのは20行目で、デリゲートにクラスとその中のメソッドへの参照を入れています。
マルチキャストデリゲーションについて
まずはこちらのコードを見てください。
24行目でBruno069クラス内の高らかな笑い声のメソッドをデリゲートに当てて次の行で呼び出しています。そして27行目で今度はアヒルの鳴き声のメソッドを同じインスタンスに入れて呼び出しています。これを見ると一つのデリゲートに委託できるメソッドは一つだけなのでしょうか。いえいえ、実は呼び出すメソッドを追加することができるのです。この24行目の後に
m += new MyDelegate(b.show2);
とすることで、このデリゲートを呼び出した際ネズミとアヒルの両方の鳴き声を聞くことができるのです。逆にこの後に
m -= new MyDelegate(b.show1);
とすればアヒルの鳴き声だけになります。このように呼び出すメソッドをいくつも増やしたりすることをマルチキャストデリゲーションと言います。声に出して言いたいですね!
デリゲートの基本を説明したところで今回は終わります。
冬の大会でこの二週間忙しかったあ〜〜🤯🤯🤯
久しぶりにこの記事書くと楽しいです😊
もう12月ですね。このブログも半年続いたお知らせが来ましたがのんびりペースすぎますね...
もっと頑張ろうっと
DateTime構造体
みなさんこんにちは🌚
寒くなってきて長袖が必要になって来ましたがタンスの中を見てみると1着しか長袖がなかったブルーノです。また最近サボりがちになっていましたが更新していきたいと思います。今回は構造体の中でも便利なDateTime構造体についてです。
DateTime構造体について
C#にもともと用意されている構造体にDateTime構造体というものがあります。この構造体の中でもNowプロパティはとても便利で、現在の日付・時刻を年からミリ秒まで取得することができるのです。直接メモリにアクセスする値型にはこのようなあらかじめ備わっている機能もあるのですね。ちょっと使ってみます。
アプリを作る際なんかに大いに役立ちそうですね。
今回はこれで終わると同時に構造体についても終わります。次回からはデリゲートとイベントというものについてやっていきます。
夜と朝が寒くなってきて朝の早起きが大変になってきました。日課の早朝ランニングも最近はやっていないし、誰か俺を律してくれえ〜〜😭