20220214のC#に関する記事は5件です。

【C#】Head First デザインパターン5章 Singletonパターン

シングルトンパターン 今回は5章シングルトンパターンをC#で勉強していきます Head Firstデザインパターン https://www.oreilly.co.jp シングルトンパターンはクラスのインスタンスの単一性を保証するデザインパターンです。 今回の例はチョコレート工場で、チョコレートと牛乳をボイラーにいれ、沸騰させたものを固めることでチョコレートバーを作ることができます。今回注目するのはボイラーの単一性なので、インスタンス周り以外に特に実装はありません。 ChocolateBoiler.cs public class ChocolateBoiler { private bool empty; private bool boiled; public ChocolateBoiler() { empty = true; boiled = false; } private static ChocolateBoiler uniqueInstance; public static ChocolateBoiler getInstance() { if (uniqueInstance == null) { uniqueInstance = new ChocolateBoiler(); } return uniqueInstance; } public void fill() { if (isEmpty()) { empty = false; boiled = false; } } public void drain() { if(!isEmpty() && isBoiled()) { empty = true; } } public void boil() { if(!isEmpty() && !isBoiled()) { boiled = true; } } public bool isEmpty() { return empty; } public bool isBoiled() { return boiled; } } 一番大事なのはgetInstanceの部分です。uniqueInstanceがもうすでにある場合、新しくインスタンスが作られないため単一性を維持することができます。 実際にボイラーを二つgetInstanceを介して作り、その二つが同じかどうかを確かめます。 Program.cs ChocolateBoiler boiler = ChocolateBoiler.getInstance(); ChocolateBoiler boiler2 = ChocolateBoiler.getInstance(); if (boiler == boiler2) { Console.WriteLine("True"); } else { Console.WriteLine("False"); } この場合Trueが返ってきます。 二つのオブジェクトをgetInstanceを介さず別々に作った場合は違う結果が返ってきます。 Program.cs ChocolateBoiler boiler = new ChocolateBoiler(); ChocolateBoiler boiler2 = new ChocolateBoiler(); インスタンスを新しく作った場合は別のインスタンスなので、Falseがかえってきます スレッドが複数ある場合、この書き方だと必ずしもインスタンスの単一性が守られるとは限りません ChocolateBoiler.cs public static ChocolateBoiler getInstance() { if (uniqueInstance == null) { uniqueInstance = new ChocolateBoiler(); } return uniqueInstance; } getInstance部分に再度注目し、スレッドが二つある場合を考えます。その二つのスレッドがif文を同時に処理した場合、最初のuniqueInstanceが作られる前に両方のスレッドでuniqueInstance == nullが実行されてしまうかもしれません。その場合インスタンスが生成される前にnullチェックが行われるので、新しいインスタンスが二つ作られてしまうことになります。それを回避する方法の一つとしてlockが挙げられます。 ChocolateBoiler.cs private static object lockObj = new object(); private static ChocolateBoiler uniqueInstance; public static ChocolateBoiler getInstance() { lock (lockObj) { if (uniqueInstance == null) { uniqueInstance = new ChocolateBoiler(); } return uniqueInstance; } } if文の中をロックすることで、一つのスレッドが処理をしている間はほかのプロセスが処理をできないようにすることができます。こうすることで、インスタンスの単一性を保つことができます。 今回の章は短かったです、次回は6章をやっていきます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【C#】関数から2つ以上の戻り値を返す方法

結論 Tuple型もしくは自作(カスタム)クラスを使います。 解説 簡単に関数から2つ以上の戻り値を返したい場合はTuple型を使用します。 使用方法は下記になります。 Tuple型で返す /// <summary> /// ユーザーの名前と年齢を返します。 /// </summary> /// <returns>item1:ユーザー名, item2:年齢</returns> private (string, int) GetUserData() { return ("山田", 25); } Tuple型からデータを取得するには下記のように記載します。 Tuple型からデータを取得する例 private (string, int) GetUserData() { return ("山田", 25); } private void User() { var tupleData = GetUserDatas(); //名前を取得 var userName = tupleData.Item1; //年齢を取得 var userAge = tupleData.Item2; } 戻り値に名前をつけることも可能です。 (@ktz_aliasさん、コメントで教えて頂きありがとうございます!) 名前付きTuple型からデータを取得する方法 // フィールド名付きタプルでメソッド定義 private (string Name, int Age) GetUserData() { return ("山田", 25); } private void User() { var tupleData = GetUserDatas(); //名前を取得 var userName = tupleData.Name; // フィールド名でアクセス //年齢を取得 var userAge = tupleData.Age; // フィールド名でアクセス } 厳格に関数から2つ以上の戻り値を返したい場合は自作クラスを使用します。 自作クラスを実装 public class User { public string Name { get; } public int Age { get; } public User(string name, int age) { Name = name; Age = age; } } 使用方法は下記になります。 自作クラス(User)で返す /// <summary> /// ユーザーの名前と年齢を返します。 /// </summary> /// <returns>Userクラス</returns> private User GetUserData() { return new User("山田", 25); } 自作クラス(User)からデータを取得するには下記のように記載します。 自作クラス(User)からデータを取得する例 private User GetUserData() { return new User("山田", 25); } private void User() { var userData = GetUserData(); //名前を取得 var userName = userData.Name; //年齢を取得 var userAge = userData.Age; } 以上です。 追記(2022/02/15) Tapleと記載しておりましたがTupleが正しい綴りでした。@apashoniさん、編集リクエストを頂きありがとうございました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C#でメールを受信するコンソールアプリを作成

C#でメールを受信するコンソールアプリを作成 はじめに C#でメール受信したときに不要なメッセージを削除したくなり、 まずは受信するアプリを作成しました。 環境 Windows 11 Pro Visual Studio 2022 取得方法 調べたら、 ・OpenPop.net ・MailKit の2種類があります。 NuGetでOpenPopをインストールしました。 作成したプログラムコード 参考ページとほぼ同じ内容で発生した問題に対処しました。 発生した問題 プロバイダのメール設定 最初に契約しているプロバイダのメール設定を済ましておく必要があります。 設定を忘れるとPOPで受信ができません。 ISO-2022-JPの問題 System.ArgumentException: 'ISO-2022-JP' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method. (Parameter 'name') の 何回か受信していると上記のエラーが出ました。 参考ページを参考に対処のコードを追加しました。 メッセージを取得順 新着順でなく反対の順番で受信しました。 結果 プライバシーがあるのでアスタリスクにしています。 受信件数 = 456 ***登録情報再入力のお願い *** IDメールアドレスを確認してください 【***】***ご利用のお知らせ *** - 支払い手続完了のお知らせ 【***】***未利用期間に関するお知らせ 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

とあるList<子クラス>をobjectに突っ込み、あとで親クラスとしてforeachしたい

背景 若干ハマったけど解決できたのでメモがてら共有させていただきます。 環境 OS: Windows 10 Pro IDE: Visual Studio 2017 Enterprise Version 15.9.40 Target Framework: .NET Framework 4.7 概要 親クラス(Parent)を継承した複数の子クラス(Child1~3)のListをポリモーフィズム的に処理したく、 保持用クラス(Hoji)のobject型変数(obj)に突っ込んで、Listとして保持しておいた。 その後、Listをforeachで反復処理しようとした際に、objからforeachで列挙可能な形に変換するのにちょっと躓いた話。 コード 定義 // 親クラス class Parent { public string Name { get; set; } } // 子クラス(1~3) class Child1 : Parent { } class Child2 : Parent { } class Child3 : Parent { } // 保持クラス class Hoji { public object obj { get; set; } } 準備 // 各子クラスに要素を持たせる。 List<Child1> childList1 = new List<Child1> { new Child1 { Name = "aaa" }, new Child1 { Name = "bbb" }, new Child1 { Name = "ccc" } }; List<Child2> childList2 = new List<Child2> { new Child2 { Name = "あああ" }, new Child2 { Name = "いいい" }, new Child2 { Name = "ううう" } }; List<Child3> childList3 = new List<Child3> { new Child3 { Name = "111" }, new Child3 { Name = "222" }, new Child3 { Name = "333" } }; // 保持用リストに格納 List<Hoji> hojiList = new List<Hoji> { new Hoji { obj = childList1 }, new Hoji { obj = childList2 }, new Hoji { obj = childList3 }, }; 処理 // こうしようとした foreach (var hoji in hojiList) { foreach (var child in hoji.obj as List<Parent>) { Console.WriteLine(child.Name); // ⇒ System.NullReferenceException: オブジェクト参照がオブジェクト インスタンスに設定されていません。 } } // こうすればできた foreach (var hoji in hojiList) { foreach (var child in hoji.obj as IEnumerable<Parent>) { Console.WriteLine(child.Name); // ⇒ "aaa" // "bbb" // "ccc" // "あああ" // "いいい" // "ううう" // "111" // "222" // "333" } } 感想 正直、なんでできるのかまで調べる余裕がなくてわかってません。 いろいろ試した結果、IEnumerableでできたってことは遅延評価が関わってるのかなーってとこで止まってます。 気が向いた方は教えていただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

タップしたところに弾を飛ばす方法

シューティングゲームで使えそうな、タップしたところにオブジェクトを飛ばす実装について 使用PC: MacBook Pro (13-inch, M1, 2020) OSバージョン: 11.5.2 Unityバージョン:2020.3.20f1 実際にゲームをプレイすると こんな感じになったら完成です! 目次 1.オブジェクトの準備 2.弾が飛ぶスクリプトの作成 3.弾の出現位置を作る 4.弾を生成するスクリプトの作成 5.オブジェクトの代入 オブジェクトの準備 ①【Hierarchy】→【Create】→【3D Object】→【Sphere】で弾オブジェクトを作成する ②名前をBallに変更しておく ③Projectビューにドラッグ&ドロップしてPrefab化しておく ④HierarchyビューのBallは不要なので消しておく ⑤PrefabにしたBallにRigidbodyをAdd Componentする 弾が飛ぶスクリプトの作成 【Project】→【Create】→【C# Script】でScriptを作成し、名前をBallControllerに変更する BallController.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class BallController : MonoBehaviour { public void Shoot(Vector3 dir) { GetComponent<Rigidbody>().AddForce(dir); } } これだけ!BallController.csをBallオブジェクトにアタッチする コードの解説 まずは弾を飛ばす用の関数 public void Shootを作ります。 その中にRigidbodyのAddForce関数で、Ballオブジェクトに物理的な力を加え移動させるコードを書いてます。 これによって勢いよくボールが飛んでいくように実装しました! 弾の出現位置を作る 【Hierarchy】→【Create】→【Create Empty】で名前をBallGeneratorに変更 このBallGeneratorからBallオブジェクトが出てくるようにしていきます! 弾を生成するスクリプトの作成 【Project】→【Create】→【C# Script】でScriptを作成し、名前をBallGeneに変更する BallGene.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class BallGene: MonoBehaviour { public GameObject BallPrefab; GameObject Ball; // Update is called once per frame void Update() { if (Input.GetMouseButton(0)) { Ball=Instantiate(BallPrefab) as GameObject; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); Vector3 worldDir = ray.direction; Ball.GetComponent<BallController>().Shoot( worldDir.normalized * 3000); } Destroy(Ball, 10.0f); } } BallGene.csをBallGeneratorオブジェクトにアタッチする コードの解説 ①変数宣言 BallGene.cs public GameObject BallPrefab; GameObject Ball; 大元になる弾のPrefabと、Instantiateする用の弾をGameObject型で宣言します。 PrefabはUnity側で代入するのでpublicをつけておいてください。 ②void Update関数の中に処理を書いていく。 BallGene.cs if (Input.GetMouseButton(0)){ Ball=Instantiate(BallPrefab) as GameObject; マウスをクリックしたときに処理をif文で書いていきます。 次に変数宣言したGameObject型のBallの中身をBallPrefabとして生成します。 ちなみに()の中に入れる数字によってクリックの処理が変わります☺️ メソッド 処理     GetMouseButtonDown(1) 右クリック時 GetMouseButtonDown(0) 左クリック時 GetMouseButtonDown(2) 中クリック時 BallGene.cs Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); Vector3 worldDir = ray.direction; カメラからRayを打ち、画面をクリックしたところの位置と方向をrayに格納します。 ray.directionでカメラからタップした座標に向かうベクトルを規定します。 BallGene.cs Ball.GetComponent<BallController>().Shoot(worldDir.normalized * 3000); BallオブジェクトについてBallController.csのShoot関数を呼び出します。 normalized変数でベクトルの正規化(長さが1のベクトルを生成)して、そこに3000の力を加えていきます。 ここの3000とかは、ご自身のゲームに合わせて数値を変えてみてください。 BallGene.cs Destroy(Ball, 10.0f); 生成した弾を10秒後に消去します。 オブジェクトの代入 HierarchyのBallGeneratorオブジェクトを選択し、Inspectorでアタッチしたスクリプト内にあるBall PrefabにBallのPrefabをドラッグ&ドロップする 以上! 参考記事 ・ボールをタップした場所に飛ばす方法と座標系の違い【Unity】
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む