月別アーカイブ: 2017年11月

Niigata.NET 3.0を開催しました #ngtnet

Niigata.NET 3.0 テックトーク+ハンズオン & .NET開発お悩み相談室 – connpass
https://ngtnet.connpass.com/event/69634/

先週土曜の11/18に通算4回目となるNiigata.NETの勉強会を開催してきました。

今年は
「アプリを作ろう! Visual C#入門」という本を書きました
のエントリで書いた通り、本を書いていたため、勉強会開催にかけるリソースが足りず、結局昨年の
Niigata.NET 2.1を開催しました #ngtnet
からちょうど1年ぶりの開催になってしまいました。

今回のテーマは、前回に引き続きテックトーク+ハンズオンです。

プログラミング初級講座 C#編 – 反復 by @AILight

最初は恒例の@AILightさんによるC#のセッションです。「変数」、「分岐」に引き続き、今回は「反復」がテーマでした。

「反復」というと、私は次のようなものをイメージしていました。

  • for使うな
  • 基本はwhile
  • 原則foreach

もちろんこのことも触れられていましたが、今回のセッションで心に残ったのは次の3つでした。

反復は「前処理」、「後処理」とパックで行う

反復というとfor、while、foreachといった「ループ」本体に目が行きがちですが、実際に反復処理を行うときは、前処理の後にループ本体、そしてループが終わったら後処理がほぼ必ずあります。したがって、この前後の処理もループの構文の直前、直後にまとめて記載しておくことが重要とのこと。こうすることで、反復処理全体を簡単に移動させることができますし、なによりループ内部で使っているものが近くにあるので、コードが追いやすく、変なこともしにくいという効果があるそうです。

私自身もほぼ何の気なしにそのように書いてはいましたが、改めてそう言われるとなるほどなとうなりました。

ループ+switchで状態を変更させて処理を行える

パズル感があり、あんまり現在は進められる方法ではありませんが、次のようにループとswitchを組み合わせて、状態遷移で処理を行うというテクニックがあるそうです。

var state = 0;
for (; ;) // 無限ループ(かわいい)
{
  switch (state)
  {
    case 0:
      Console.WriteLine("Header");
      state = 1;
      break;
    case 1:
      if (!recordExists)
      {
        state = 2;
        break;
      }
      Console.WriteLine("record");
      break;
    case 2:
      if (recordExists)
      {
        state = 0;
      }
      else
      {
        state = 3;
        break;
      }
      Console.WriteLine("Footer");
      break;
    case 3:
      Console.WriteLine("Summary");
      state = 4;
      break;
  }
  // state = 4
  break; // ループ終了
}

まず使うこともないでしょうが、いざというときの「腕力」として覚えておこうと思いました。

コレクションの要素とindexを同時に使うときはSelect((element, index) => …)を使う

反復処理を行うとき、コレクションの要素とindexを同時に扱いたいケースがたまにあります。

そんな時私はこれまで、次のようにループの外でindex用変数を宣言してやっていました。

var index = 0;
foreach (var element in collection)
{
    Console.WriteLine($"element: {element}, index: {index}");
 index++;
}

しかし、LINQの要素とindexを取るSelectメソッドを使ってからforeachすることで、ループの外での変数宣言が不要になるとのこと。

foreach (var item in collection.Select((element, index) => new { element, index }))
{
    Console.WriteLine($"element: {item.element}, index: {item.index}");
}

構文自体は知っていましたが、これまでそんなに使っていなかったので、今後は積極的に使っていこうと思います。

アプリ開発ハンズオン by @masaru_b_cl

「アプリを作ろう! Visual C#入門」のじゃんけんアプリをネタに、本を見ないでやってみようというハンズオンをしました。資料はこちら。

当日はラウンド制まではたどり着かず、代替全員があいこならもう一回勝負するというところまで出来たら時間切れになりました。

参加者の皆さんの様子を見ていると、普段仕事で作成するアプリと違い、ゲームは「状態」を強く意識しないといけなかったり、画像をリソースを使って扱ったりしないといけないため、案外手こずっているようでした。

そんななか、何とかは私は著者の面目を守り、スライドの説明後に超速でコーディングして何とか一つの実例コードを書き上げることができました。セッションの最後では、そのコードをもとに開設&コードレビュー会を行いました。

その際説明させてもらったのは、次のような内容です。

  • コントロールのプロパティ直接扱っちゃダメ、絶対!
    • いったん変数に受ける
    • これによりメソッド切り出しが容易になる
    • さらに他の型に追い出すことも容易になる
  • 勝敗判定は次のような感じでやると良い
    • まずグー、チョキ、パーを0,1,2でも列挙型でもよいので一段抽象化する
      • PictureBoxコントロールのImageプロパティで判断してはいけない
    • 判定は次の順
      • プレイヤーと敵の手が一緒ならあいこでreturn
      • 愚直に勝ちパターン3つをor判定
        • プレイヤー:グー && 敵:チョキ
          or プレイヤー:チョキ && 敵:パー
          or プレイヤー:パー && 敵:グー
      • 勝ちでなければ負け
  • グー、チョキ、パーの画像は何らかのテーブルで管理
    • グー、チョキ、パーを指定すると取れる
    • 例では配列を使った
      • 列挙型をキーとするDictionaryだと実行時例外が起きなくてよいのではというアドバイスあり

あと、書籍では実装しなかったのですが、じゃんけんを始めた後、敵の手が次々とランダムに変わりルーレット状になるようにも実装しました。これにはTimerコンポーネントを追加し、次の要領でやりました。

  • スタートボタンが押されたらプレイヤーの手を消してからタイマー開始(Enabled = true)
  • タイマーのTickイベントハンドラーで敵の手をランダムに表示
  • プレイヤーが手を選んだらタイマー停止(Enabled = false)
  • あいこならプレイヤーの手を消してからまたタイマー開始
  • 勝ちか負けなら手を選べなくしてスタートボタンを押されるまで待機

やってみるまでは、非常に簡単なアプリなのでどれだけ盛り上がるかちょっと不安だったのですが、実際にはそれぞれの人でやり方やプログラミングスタイルが異なったり、持っている知識レベルに差があるため、手が止まってしまう箇所がいろいろあって都度アドバイスして直してもらったりと、結構充実した時間となりました。また別テーマでハンズオンをやってみるのもよいなと思えた貴重な時間となりました。(ハッカソンもできたらやりたい)

.NET開発相談室

アプリハンズオンが思いのほか楽しく時間を延ばしてやってもらったので、今回は.NET相談室は取りやめにしました。ただ、次やるときは事前に相談したいことを出してもらってからやるようにしようかなと思いました。

懇親会

次のような濃密な議論ができた時間でした(しれっと

https://twitter.com/84taka0310/status/931819903601885184

次回に向けて

開催ペースが落ちてしまったので、何とか年2回ペースをキープしたいところです。ひとまず5月くらいを目途に、またやっていこうと思います。

あわせて読みたい