モチベーションも大事だと思うので覚書として使用します。
九週目の感想
今後はさらに基本学習から目的のための内容にしていきたい。あと、お寿司食べたい🍣
#自作してみた(DateTime使った何か)
今回の学習で作ったコード(折畳)
using System;
using System.IO;
class Tester
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
public string Lang { get; set; }
public string Response { get; set; }
public string Rating { get; set; }
public string Specialty { get; set; }
//public int Counter { get; }
}
class TestTester
{
static void Main()
{
Tester t = new Tester();
Console.Write("テスターの現在の人数 : ");
// 既定値外
int numOfTesters = -1;
// 文字は代入されずwhileへ、既定値外は代入されwhileへ、既定値は代入されwhileパス
if (int.TryParse(Console.ReadLine(), out var nType))
{ numOfTesters = nType; }
while (numOfTesters <0)
{
Console.Write("retype number of testers. ");
if (int.TryParse(Console.ReadLine(), out nType))
numOfTesters = nType;
}
Console.Write("name : ");
t.Name = Console.ReadLine();
Console.Write("age : ");
if (int.TryParse(Console.ReadLine(), out var nInput))
{ t.Age = nInput; }
while (t.Age < 9 || t.Age > 99)
{
Console.Write("retype age(10-98). ");
if (int.TryParse(Console.ReadLine(), out nInput))
t.Age = nInput;
}
Console.Write("country : ");
t.Country = Console.ReadLine();
Console.Write("lang : ");
t.Lang = Console.ReadLine();
Console.Write("response : ");
t.Response = Console.ReadLine();
Console.Write("rating : ");
t.Rating = Console.ReadLine();
Console.Write("specialty : ");
t.Specialty = Console.ReadLine();
int counter = ++numOfTesters;
Console.WriteLine("\n入力内容の確認:");// 以前の書き方
var testerString =
$"Tester number: No.{counter}\n" +// もっといい書き方
$"Tester Name: {t.Name}\n" +
$"Tester Age: {t.Age}\n" +
$"Tester Country: {t.Country}\n" +
$"Tester Lang: {t.Lang}\n" +
$"Tester Response: {t.Response}\n" +
$"Tester Rating: {t.Rating}\n" +
$"Tester Specialty: {t.Specialty}\n";
Console.Write(testerString);
byte nInput3 =3;
Console.Write("\n保存しますか?(1/新規保存 2/上書き保存 0/保存しない)");
if (Byte.TryParse(Console.ReadLine(), out var nType3))
{ nInput3 = nType3; }
while (nInput3 <0 || nInput3 >2)
{
Console.Write("\n入力ミスです。保存しますか?(1/新規保存 2/上書き保存 0/保存しない)");
if (Byte.TryParse(Console.ReadLine(), out nType3))
{ nInput3 = nType3; }
}
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string personInfo, fileName, fileName2, filePath;
fileName = "Person_final.txt";
fileName2 = "Person_final" + DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".txt";
// fileName2は既存ファイルあるのに新規保存した場合の命名規則 (挙動→switch case1)
filePath = folderPath + "\\" + fileName;
personInfo = testerString;
switch (Ans)
{
case 0:// 保存しない
Console.WriteLine("保存されませんでした。");
break;
case 1:// 新規保存
if (File.Exists(filePath))
{
Console.WriteLine("タイムスタンプ付で新規保存されました。。");
filePath = folderPath + "\\" + fileName2;
File.WriteAllText(@filePath, personInfo);
}
File.WriteAllText(@filePath, personInfo + Environment.NewLine);
Console.WriteLine("以下のタイトルで保存されました。" + fileName2);
break;
case 2:// 上書き保存
Console.WriteLine("上書き保存されました。");
File.AppendAllText(@filePath, Environment.NewLine + personInfo + Environment.NewLine);
break;
}
}
}
内容は架空スタッフを登録するシステムで、
それぞれ分かった範囲でパーツ作成して実装していきました。
考えるのは楽しいがシンプルな機能なのに実際やると大変だった。
何回も失敗して回り道しながら徐々にシンプルにしていった。
あと、設計(アーキテクチャ)がパーツだけだと可読性悪かったりエラー頻発する事を知った…
全体的に考えが甘かった、でも、それを含めても楽しい。FPSと同様に競技になるのも分かる。
2018.11.21: personInfoの短縮化ができました。
2018.11.20: 人数入力・年齢入力・保存入力の例外処理を追加しました。
具体的には、文字は代入されず既定値外でwhileへ、既定値外は代入されwhileへ、既定値は代入されwhileパス
##説明
設計
①データ登録(プロパティ)
②ユーザ入力(ReadLineと新規保存と上書き保存)
③制御文(switch)
(肝心のDateTimeは③制御文の際無理やり導入…本当はPredicateで条件検索入れたかったけど端折った)
###①データ登録作成(プロパティ)
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
public string Lang { get; set; }
public string Response { get; set; }
public string Rating { get; set; }
public string Specialty { get; set; }
//public int Counter { get; }使ってない
登録用にNameやAgeの情報をget
したり…
(Console.Write("name : "); t.Name = Console.ReadLine();
…etc)
表示用にpersonInfoに情報をset
するため。
(personInfo = ("No." + counter) + Environment.NewLine
...etc)
雑記
###②ユーザ入力(ReadLineと新規保存と上書き保存) set用にユーザ入力欄実装して、ついでに書き出しもしたくなるので調べて実装。
class TestTester
{
static void Main()//ここでの入力がプロパティクラスにsetされる
{
Console.Write("テスターの現在の人数: ");
// 既定値外
int numOfTesters = -1;
// 文字は代入されずwhileへ、既定値外は代入されwhileへ、既定値は代入されwhileパス
if (int.TryParse(Console.ReadLine(), out var nType))
{ numOfTesters = nType; }
while (numOfTesters <0)
{
Console.Write("retype number of testers. ");
if (int.TryParse(Console.ReadLine(), out nType))
numOfTesters = nType;
}
Tester t = new Tester();
Console.Write("name : ");// 名前
t.Name = Console.ReadLine();
Console.Write("age : ");// 年齢
if (int.TryParse(Console.ReadLine(), out var nInput))
{ t.Age = nInput; }
while (t.Age < 9 || t.Age > 99)
{
Console.Write("retype age. ");
if (int.TryParse(Console.ReadLine(), out nInput))
t.Age = nInput;
}
Console.Write("country : ");// 国籍
t.Country = Console.ReadLine();
Console.Write("lang : ");// 言語
t.Lang = Console.ReadLine();
Console.Write("response : ");// 対応率
t.Response = Console.ReadLine();
Console.Write("rating : ");// 満足度
t.Rating = Console.ReadLine();
Console.Write("specialty : ");// 得意分野
t.Specialty = Console.ReadLine();
int counter = ++numOfTesters;
// counterは先程変換したint型の人数値numOfTestersを、+1にする事で何人目。という値になる
Console.WriteLine("\n入力内容の確認:");// 以前の書き方
var testerString =
$"Tester number: No.{counter}\n" +// もっといい書き方
$"Tester Name: {t.Name}\n" +
$"Tester Age: {t.Age}\n" +
$"Tester Country: {t.Country}\n" +
$"Tester Lang: {t.Lang}\n" +
$"Tester Response: {t.Response}\n" +
$"Tester Rating: {t.Rating}\n" +
$"Tester Specialty: {t.Specialty}\n";
Console.Write(testerString);
byte nInput3 =3;
Console.Write("\n保存しますか?(1/新規保存 2/上書き保存 0/保存しない)");
if (Byte.TryParse(Console.ReadLine(), out var nType3))
{ nInput3 = nType3; }
while (nInput3 <0 || nInput3 >2)
{
Console.Write("\n入力ミスです。保存しますか?(1/新規保存 2/上書き保存 0/保存しない)");
if (Byte.TryParse(Console.ReadLine(), out nType3))
{ nInput3 = nType3; }
}
string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string personInfo, fileName, fileName2, filePath;
fileName = "Person_final.txt";
fileName2 = "Person_final" + DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".txt";
//fileName2は既存ファイルあるのに新規保存した場合の命名規則 (挙動→switch case1)
filePath = folderPath + "\\" + fileName;
personInfo = testerString
//保存内容代入。どうシンプルに代入すればいいのか…//解決
書き出すデータ内容を変数や配列にして代入したかったけど
同一メソッド内がだめなのか何がダメか分からずpersonInfoはt.Age t.Name…と一個一個書いた。
同じく上書きしたデータが前データと繋がるのを避けるため、
複数行の改行したかったけどよく分からず + Environment.NewLineを複数入れた。
###③新規/上書き選択制御文作成過程
switch
が最適か分からないけどシンプルそうなので選んだ。
switch (Ans)
{
case 0:// 保存しない
Console.WriteLine("保存されませんでした。");
break;
case 1:// 新規保存
if (File.Exists(filePath))
{
Console.WriteLine("タイムスタンプ付で新規保存されました。");
filePath = folderPath + "\\" + fileName2;
File.WriteAllText(@filePath, personInfo);
}
File.WriteAllText(@filePath, personInfo + Environment.NewLine);
Console.WriteLine("以下のタイトルで保存されました。" + fileName2);
break;
//using (StreamWriter outputFile = new StreamWriter(filePath))
// outputFile.WriteLine(personInfo);
//https://qiita.com/t_sato310/items/6c6ec79f4487a52b6b9e
//https://www.csharpstar.com/create-read-write-text-file-csharp/
//色々な保存方法あるようだ…
case 2:// 上書き保存
Console.WriteLine("上書き保存されました。");
File.AppendAllText(@filePath, Environment.NewLine + personInfo + Environment.NewLine);
break;
}
ガード節とか考えず単純な小さなスイッチを作って大きなリモコン?になる感覚が楽しい。
また、ローカライズされたDateTimeを表示したくて結構時間使った。結果無理だったけど…
ローカライズされたDateTimeはコードで完結無理
以上。以下デリゲートやDateTime仕様
#━━デリゲート メソッドを参照する━━
①まずクラス外で宣言してdelegate void DeleName(int a, int b)
②MainでデリゲートをNewインスタンス化か代入new DeleName(c.Minus)
③最後に引数代入と共に呼び出しd1(2, 1)
←記述方法
delegate void DeleName(int a, int b);// デリゲート宣言はクラス外でする。
class Calc
{
public void Minus(int a, int b)// 呼び出したいメソッド
{
Console.WriteLine($"{a} - {b} = {a - b}");
}
}
class Program
{
static void Add(int a, int b)// 呼び出したいメソッド
{
Console.WriteLine($"{a} + {b} = {a + b}");
}
static void Main(string[] args)// Mainでは、デリゲートをNewインスタンス化し代入値と共に呼び出し。
{
Calc c = new Calc();// cは別クラス呼び出してデリゲートをNewインスタンス化可能にしている
DeleName d1 = new DeleName(Add);// インスタンス化(メソッドへの参照)
DeleName d2 = new DeleName(c.Minus);// インスタンス化(メソッドへの参照)
d1(2, 1);// インスタンス化したd1の呼び出し。d1,d2が(int a=2 int b=1)と代入された上で呼び出される。
d2(2, 1);// インスタンス化したd2の呼び出し。結果はAdd, c.Subそれぞれのメソッドと等価。
}
}
//2 + 1 = 3
//2 - 1 = 1
デリゲート(delegate)は、 メソッド専用の参照型です。※関数のように見えますが型です。
そして()内は引数リスト(引数の型と数)が同じである必要があります。引数無しは下部Actionにて。
一度定義すればいつでもどこかにあるメソッドを呼び出せます。
宣言は、クラスの前にdelegate型 戻り値型 名();
とします。
例)int MethodName(int x, double y)
というメソッドを参照できるデリゲート宣言は、
delegate int DelegateName(int a, double b);
のようになります。
また上記の場合の参照時はDelegateName dn = new DelegateName(MethodName)
このようにNewインスタンス(呼び出すメソッド名)にします。
基本的なコード例をここに示します
class Program
{
public delegate void Print(int value);//宣言
static void Main(string[] args)
{
Print printDel = PrintNumber;//代入
printDel(100000);
printDel(200);
// Print delegate points to PrintMoney//代入
printDel = PrintMoney;
printDel(10000);
printDel(200);
}
public static void PrintNumber(int num)//参照
{
Console.WriteLine("Number: {0,-12:N0}",num);
}
public static void PrintMoney(int money)//参照
{
Console.WriteLine("Money: {0:C}", money);
}
}
このように、同じクラスならNEwインスタンスはなく普通に=で代入すればよい
##マルチキャストデリゲーション 演算子で追加、削除
Newインスタンス/代入する際+
や-
演算子で別メソッドを追加、削除できる。
delegate void DeleName(int a, int b);// デリゲート宣言はクラス外でする。
class Calc
{
public void Minus(int a, int b)// 呼び出したいメソッド
{
Console.WriteLine($"{a} - {b} = {a - b}");
}
}
class Program
{
static void Add(int a, int b)// 呼び出したいメソッド
{
Console.WriteLine($"{a} + {b} = {a + b}");
}
static void Main(string[] args)// Mainでは、デリゲートをNewインスタンス化し代入値と共に呼び出し。
{
Calc c = new Calc();// cは別クラス呼び出してデリゲートをNewインスタンス化可能にしている
DeleName d1 = new DeleName(Add);// インスタンス化(メソッドへの参照)
DeleName d2 = new DeleName(c.Minus);// インスタンス化(メソッドへの参照)
d2 += d2;
d1(2, 1);// インスタンス化したd1の呼び出し。d1,d2が(int a=2 int b=1)と代入された上で呼び出される。
d2(2, 1);// インスタンス化したd2の呼び出し。結果はAdd, c.Subそれぞれのメソッドと等価。
}
}
//2 + 1 = 3
//2 - 1 = 1
//2 - 1 = 1
このように、追加/削除できました (全部削除-=
した場合呼び出すメソッドなくなりエラー)
##匿名メソッド Mainで同時宣言
匿名メソッドは名前のないメソッドです。
正確には名前部分delegateとして、Main内でメソッドと同時宣言できます。
今まで外部にメソッド作成していたためNewインスタンスで呼び出ししていましたが省略できます。
使用には、
今までDelegateName dn = new DelegateName(引数);
匿名 DelegateName dn = delegate(引数) {処理文};
基本的なコード例をここに示します
public delegate void Print(int value);
static void Main(string[] args)
{
int i = 10;
Print prnt = delegate(int val) {
val += i;
Console.WriteLine("Anonymous method: {0}", val);
};
prnt(100);
}
このように、簡略化できます。ラムダ式を用いる事でさらに簡略化できます
###ラムダ式 簡略化
ラムダ式は1930年代に考案された計算方式です。
主にLinQで用いますが匿名メソッドに用いる事もできます。
使用には、
今までDelegateName dn = new DelegateName(引数);
匿名 DelegateName dn = delegate(引数) {処理文};
ラムダDelegateName dn = (引数) => {処理文};
全部まとめたコード
class Calc
{
public void Minus(int a, int b)// 呼び出したいメソッド
{
Console.WriteLine($"{a} - {b} = {a - b}");
}
}
class Program
{
static void Add(int a, int b)// 呼び出したいメソッド
{
Console.WriteLine($"{a} + {b} = {a + b}");
}
static void Main(string[] args)// Mainでは、デリゲートをNewインスタンス化し、d1,d2が(int a=2 int b=1)と代入された上で呼び出された。
{
Calc c = new Calc();// cは別クラス呼び出してデリゲートをNewインスタンス化可能にしている
DeleName d1 = new DeleName(Add);// インスタンス化
DeleName d2 = new DeleName(c.Minus);// インスタンス化
d2 += d2;// +=演算子
d1(2, 1);// インスタンス化したd1の呼び出し。d1,d2が(int a=2 int b=1)と代入された上で呼び出される。
d2(2, 1);// インスタンス化したd2の呼び出し。結果はAdd, c.Subそれぞれのメソッドと等価。
DeleName d3 = delegate (int a, int b) { Console.WriteLine(a + b); };//匿名メソッド
d3(2, 1);//匿名メソッド呼出
DeleName d4 = (int a, int b) => { Console.WriteLine(a + b); };//ラムダ式
d4(2, 1);
}
}
このように、6文字位簡略化できました。ラムダ式は主にLinQで用います/font>
##定義済みdelegate (Func Action)
定義済みdelegateはクラスライブラリ(調べると色々ある)で定義されているラムダ式を格納出来る型で、
①「Action」と「Func」で既に宣言してある為、「delegate」の宣言が必要ない。
②引数無しやstring、戻り値がvoidのラムダ式を代入できたり、汎用的に色々な型に対応できます。
裏ではジェネリックという機構を用いているようです。今回は引数無しvoid値返すActionを書きます。
戻り値を持つdelegateがFunc
戻り値を持たない(void値返す)delageteがAction
基本的なコード例をここに示します
namespace C.p.act
{
public class Name
{
private string instanceName;
public Name(string name)
{
this.instanceName = name;
}
public void DisplayToConsole()
{
Console.WriteLine(this.instanceName);
}
public void DisplayToWindow()
{
Console.WriteLine(this.instanceName);
}
}
public class LambdaExpression
{
public static void Main()
{
Name testName = new Name("Koani");
Action showMethod = () => testName.DisplayToWindow();
//等価 Action showMethod = delegate() { testName.DisplayToWindow();} ;
//showMethodというActionが、Main内Newインスタンス(newName"Koani")の、
//DisplayToWindow呼ぶ。呼ばれたthis.instanceNameはstringのKoani出力する
//つまり、showMethodはKoani
showMethod();
}
}
}
##Predicate 条件検索
特定の条件(リストからの名前や年齢による検索等)を満たすものだけを抽出するようなメソッドを書きたいとき、
条件式をデリゲートにして引数に渡します。外から与える条件式をPredicate(述語)といいます。
(覚えれる気がしないので、この構文で検索できる位で端折る)
この構文Predicate<Person> oscarFinder = (Person p) => { return p.Name == "Oscar"; };
Person oscar = people.Find(oscarFinder);
StackOverFlow
#構造体
構造体(structure)は、クラスとよく似ています。
違いはクラスは参照型、構造体は値型のデータであるという点です。
また、参照型が必要なくて軽量のオブジェクトを表す場合適していると言われています。
ただ現在はあまり使わないとどこかで見たので構文で終えます。
使用には、struct 名前 {}
とします。
また、構造体にはインターフェイスが使えます。
その場合、struct 名前 : インターフェイス {}
とします。
基本的なコード例をここに示します
namespace Structure1
{
struct MyStruct
{
public int x;// 宣言のみ。初期化はMain関数でないと無理。
public void Show()
{
Console.WriteLine($"x={x}");
}
}
class structure
{
public static void Main()
{
MyStruct m;//初期化
m.x = 10; //初期化
m.Show();
}
}
}
##DateTime
DateTimeは、その名の通り現在時刻を表示します。
使用には、Console.WriteLine(DateTime.Now);
2018/11/09 17:40:45
または、文字列表示する際は、
DateTime dt = DateTime.Now; string s = dt.ToString("yyyy年MM月dd日 HH時mm分ss秒 K"); Console.WriteLine(s);
2018年11月09日 17時52分33秒 +09:00
とします。
基本的なコード例をここに示します
namespace DateTime1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(DateTime.Now);// 2018/11/09 17:54:54
DateTime dt = DateTime.Now;
string s = dt.ToString("yyyy年MM月dd日 HH時mm分ss秒 K");
Console.WriteLine(s);// 2018年11月09日 17時54分54秒 + 09:00
// KはUTCとの時差表示(JPは+9)
}
}
}
using System;
using System.Globalization;
public class Example
{
public static void Main()
{
DateTime localDate = DateTime.Now;
String[] cultureNames = { "en-US", "ja-JP", "th-TH",
"de-DE", "ru-RU" };
foreach (var cultureName in cultureNames)
{
var culture = new CultureInfo(cultureName);
Console.WriteLine($"{cultureName}: {localDate.ToString(culture)}");
// ローカル表記。ローカル時刻は作るしかない?
}
}
}
このように、他にも色々表示方法があります。ミリ秒表示、Clture-names...etc
#リフレクション プロパティをまとめて取得/設定
次回イベント