C#基本

# 目次
 - C#とは
 - 特徴
 - HelloWorld
 - 標準入力
 - 標準出力
 - 変数
 - ランダム
 - 条件分岐
 - DateTime構造体
 - 繰り返し処理
 - 配列
 - Listクラス
 - 多次元配列
 - Dictionary
 - メソッド
 - スコープ
 - LINQ
 - クラス
 - アクセス修飾子
 - static
 - プロパティ
 - クラスの継承
 - 名前空間
 - 例外処理(Exception)

# C#とは
.NET Framework上で動作するオブジェクト指向言語

# HelloWorld
```C#
using System;
public class Hello{
	public static void Main(){
		Console.WriteLine("Hello world");	//セミコロンを忘れない
	}
}
```

# 標準入力、標準出力、標準エラー出力
System.Consoleのメソッドを使用する

```C#
//標準入力
System.Console.ReadLine()  //String型として読み込まれる
//数値に変換するには、intのParseメソッドを使用する
int.Parse(System.Console.ReadLine())

//標準出力
System.Console.WriteLine(/*出力内容*/);  //末尾に改行コードを挿入
System.Console.Write(/*出力内容*/);      //末尾に改行コードを挿入しない

//標準エラー出力
System.Console.Error.WriteLine(/*出力内容*/);

//コードの頭でSystemの使用を宣言することでConsole以降から記述可能
using System;
Console.WriteLine("~~");
```


# 変数
```C#
//宣言：データ型と一緒に宣言する
string 変数名 = 値(文字列);
int    変数名 = 値(数値);
var    変数名 = 値;	      //var で宣言すると値に応じて型が自動で決定される

//変数と文字列の結合
System.Console.WriteLine(変数 + "文字列");
```

# 配列
```C#
//宣言と初期化
型[]     配列名 = new 型[要素数];    //既存の配列の上書き(リセット)にも使える
string[] 配列名 = {要素, 要素};		//文字列を格納する配列
int[]    配列名 = {要素, 要素};		//数値を格納する配列

//要素の追加
配列名[インデックス] = 値;

//取り出し
Console.WriteLine(配列名[インデックス]);

//要素を区切って出力
Console.WriteLine(string.Join(",", 配列名));
// => 要素,要素,要素

//要素数
配列名.Length
```
# 多次元配列
```C#
//宣言と初期化
string[] array1 = {"bar", "foo"};
string[] array2 = {"var", "hoo"};
stying[][] array3 = {array1, array2};

//直接定義する
string[][] array4 = {
	new string[] {"bar", "foo"},
	new string[] {"var", "hoo"}
};

//new演算子を用いて多次元配列を定義
//6x5の2次元配列
int[][] array5 = new int[5][];
for (int i = 0; i < array5.Length; i++) {
	array5[i] = new int[6];
}
```

# Collection
```C#
//導入
using System.Collections.Generic;
//Generic => 宣言時にデータ型を指定するクラス
```

### Listクラス
配列と異なり、宣言時に要素数の上限を決める必要がない

```C#
//宣言
var List名 = new List<型>();

//要素の追加
List名.Add(要素);				//末尾に追加
List名.Insert(インデックス, 要素);	//指定の箇所に追加

//要素の削除
List名.Remove(要素);

//要素数
List名.Count;
```

## 文字列を分割して配列化
```C#
文字列.Split(分割文字);

//配列に代入
string[] = array = data.Split(',');
```



# Dictionary
## 作成
```C#
using System.Collections.Generic;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var Dictionary名 = new Dictionary<keyの型, valueの型>();
```

## 要素の追加
```C#
Dictionary名.Add(key, value);
```

## 要素の取得
```C#
Dictionary名[key];
```

## 要素数
```C#
Dictionary名.Count;
```

## valueの更新
```C#
Dictionary名[key] = 値;
```

## 要素の削除
```C#
Dictionary名.Remove(key);
```
## ループ処理
```C#
//KeyValuePair構造体を用いる
foreach (KeyValuePair<string, string> 変数 in Dictionary名 {
	Console.WriteLine(変数.Key);
	Console.WriteLine(変数.Valu);
}

//varでも可
foreach (var 変数 in Dictionary名) {
	処理
}
```

# ランダム
Randomクラスを使用してランダムな数字を取得する

```C#
var random = new Random();
var number = random.Next()
```
## Nextメソッド
0以上の数値をランダムに生成する
Nextメソッドで生成される数の範囲の指定は以下の通り

```C#
var random = new Random();
var number = random.Next(1, 101);	//1以上101未満
var number = random.Next(10); //0以上10未満
```

#条件分岐
## if文
構文

```C#
if (条件式) {
	処理;
} else if {
	処理;
} else {
	処理;
}
```

# DateTime構造体
https://docs.microsoft.com/ja-jp/dotnet/api/system.datetime?redirectedfrom=MSDN&view=netcore-3.1

```C#
var today = DateTime.Today;	//今日
Console.WriteLine(today);
// => mm/d/yyyy 12:00:00 AM
Console.WriteLine(today.Year);	//今日の西暦年
// => yyyy
Console.WriteLine(today.Month);	//今日の月
// => m
Console.WriteLine(today.Day);	//今日の日
// => d
```

# 繰り返し処理
## while
```C#
var i = 0;			//カウンタ変数
while (i <= x);	{	//繰り返しの条件
	処理;
	i++;			//カウンタ変数のインクリメント
}
```

## for
```C#
for (カウンタの初期化; 繰り返しの条件; カウンタの更新){
	処理;
}

for (i = 0; i < x; i++) {
	処理;
}

//カウンタはforの前でも宣言できる
int i;
for (i = 0; i < x; i++) {
	処理;
}
```

## foreach
```C#
string[] 配列名 = {要素, 要素};
foreach(string 変数 in 配列名) {
	繰り返す処理
}
```



# メソッド
## 定義
```C#
//メソッドはクラスの中に定義する
public class Methods {
	public static void Method1() {
		処理
	}
}
```

## 呼び出し
```C#
public class Methods {
	public static void Main() {		//MainメソッドはC#のプログラムの実行じに最初に自動的に呼び出される
		Method1();
	}
	public static void Method1() {
		処理
	}
}
```
## 引数
引数を設定する際は、データ型も指定する

```C#
public static void Method1 (int a, string str) {
	Console.WriteLine(a);
	Console.WriteLine(str);
}
```

### デフォルト値
```C#
public static void Method1 (int a, string str = "foo") {
	Console.WriteLine(a);
	Console.WriteLine(str);
}
//デフォルト値を持つ引数はデフォルト値を持たない引数より後で定義する
```

### 名前付き引数(ラベル)
```C#
public static void Main() {
	Method1(str: “var”, a: "hoo");
	Method1(str: “var”);
}

public static void Method1 (string a = "bar", string str = "foo") {
	Console.WriteLine(a);
	Console.WriteLine(str);
	Console.WriteLine();
}
//実行結果
//hoo
//bar
//
//bar
//var
```

### 可変長引数
```C#
public static void Method(params string[] lines) {
	//呼び出し時に指定した全ての引数が配列`lines`に追加されて処理される
	foreach (string line in lines) {
		Console.WriteLine(line);
	}
}
```

## 戻り値
戻り値を設定する場合、データ型を指定する

```C#
public static int Method(int a, int b) {
	return x + y;
}
```

# スコープ
## 変数のスコープ
メソッド内で定義された通常の変数(ローカル変数)のスコープはメソッド内

```C#
public class Program {
	public static void Main() {
		int a = 3;
		Console.WriteLine(a);
		Method1();
		Console.WriteLine(a);
	}
	public static void Method1() {
		int a = 30;
		Console.WriteLine(a);
	}
}
//実行結果
//3
//30
//3
```

ブロックの中で宣言された変数のスコープはブロック内<br>
(ブロック => {}で囲まれた部分)

```C#
public static void Main(){
	num = 6;
	if (num % 2 == 0) {
		string message = "Even number";
		Console.WriteLine(message):
	}
	Console.WriteLine(message);	//これはエラーが出る
}
```

# LINQ
LINQを使うとデータの集まりに対する処理を簡単に行えるようになる
## 導入
```C#
using System.Linq;
```

## 最大値
・最初内を求める
LINQのMax、Minメソッドを用いると、配列内の数値について、最大値、最初内が求められる

```C#
using System;
using System.Linq;
public class Program{
    public static void Main() {
        int[] nums = {11, 46, 27};
        Console.WriteLine(nums.Max());
        Console.WriteLine(nums.Min());
    }
}
//実行結果
//46
//11
```

# クラス
## クラスの定義
```C#
public class クラス名 {
}
```
## 変数
```C#
public class クラス名 {
	private string 変数名;				//フィールド
	
	public クラス名(string 変数名) {		//コンストラクタ
		this.変数名 = 変数名;
	}
}
```

### フィールド
クラスに定義されている変数
オブジェクトが存在する限り値が保持される

### コンストラクタ
名前がその型の名前(クラス名)と同じメソッド
クラスからオブジェクトを作るために呼び出されるメソッド

#### オブジェクト生成時にコンストラクタに値を渡してフィールドを初期化する
```C#
var 変数名 = new クラス名(コンストラクタに渡す値);
```

# アクセス修飾子
public => プログラム中のどこからでも呼び出せる
private => 定義されているクラスの中でのみ呼び出せる
internal => 同じプロジェクト(同じ[アセンブリ](https://docs.microsoft.com/ja-jp/dotnet/standard/assembly/index)内の任意のコード)から呼び出せる
他にも、

 - protected
 - protected internal
 - private protected

などがある

## アクセス修飾子の省略
クラス内で定義されているもののアクセス修飾子を省略すると、privateとして扱われる
クラス自体のアクセス修飾子を省略すると、internalとして扱われる

# static
staticがついた変数やメソッドは、全てのオブジェクトで共通して利用できる
オブジェクトを作らなくてもアクセスできる

# プロパティ
プライベートフィールドの読み書き及び計算をする際に利用する機能
プライベートフィールドは、クラスの外からアクセスできないため、そのフィールドにアクセスするパブリックのメソッドや、プロパティが必要となる 

```C#
public static int Num {
	get {				//読み込み
		return num;
	}
	private set {			//セッターをprivateにすることとでクラス外での書き換えを防ぐ
		num = value;		//書き込み
	}
}

//省略した記述
public static int Num {get; private set;}
```

# クラスの継承
基底クラス => 派生クラス
継承したクラスのメソッド、変数を使用できる

```C#
class 派生クラス名 : 基底クラス名 {
	public 派生クラス名(型 派生クラスコンストラクタ) : base(基底クラスコンストラクタ) {
	}
}
```

## メソッドのオーバーライド
class Class1 {
	public string Value {get; private set;}

	public Object (string value) {
		Value = value;
	}
	
	public virtual void Method1() {		//基底クラスのメソッドを仮想メソッドにする
		処理
	]
}

class Class2 : Class1 {
	public Class2(string value) : base(value) {
	}
	
	public override void Method1() {
		オーバーライドした処理
	}
}
```

## メソッドのオーバーロード
同名のメソッドを、引数の数、引数の型によって区別する
=> 引数の違いで処理を分けることができる

# 名前空間
複数のクラスを管理するまとまり

## 標準ライブラリにおける名前空間の例
### System
一般的に使用されるクラス

 - Arratクラス
 - Consoleクラス
 - Exceptionクラス
 - Mathクラス
 - Randomクラス

など
### System.IO
データやッファイルの入出力等に関連するクラス

 - Fileクラス
 - FileiInfoクラス
 - FileStreamクラス
 - Directoryクラス
 - Pathクラス

など

## 名前空間からの呼びだし
```C#
名前空間.クラス.メソッド();

System.Console.WriteLine(文字列);

using System;	//usingで名前空間を指定すると、以降の記述で名前空間を省略可能
```

# 例外処理(Exception)
## C#プログラムの実行手順
1. コンパイル
  -  実行できる形式に変換
  -  コンパイルエラー:綴り間違い、文法の間違い
2. 実行する
  -  順次、計算や処理をおこなう
  -  実行時エラー:計算できない、ファイルがない

2の実行時エラーに対応するために例外処理を記述する

## 例外処理の機能
 - try
  -  予めコードを指定して、プログラム実行時に、処理の問題を検出する
 - catch
  -  問題を検出した時、どのように対応するか記述しておく
 - throws
  -  対応を記述していない場合、メソッドの呼び出し元に対応を任せる

### 例外が発生する例
 - 0で除算
  -  DivideByZeroException
 - 数値変換で、数字でない文字列を指定
  -  FormatException
 - 引数に不正なnullが渡される
  -  ArgumentNullException
 - 配列の範囲外アクセス
  -  IndexOutOfRangeException
 - ファイルが存在しない

例外処理を記述していないと`Unhandled Exception’エラーが発生し、発生時点で強制終了する

## 例外処理の記述
```C#
try {
	例外を検出したいコード
}
catch (Exception e) {		//例外ハンドラ	  e は例外の詳細情報を格納したExceprionオブジェクト
	例外発生時の処理
	//例)
	Console.WriteLine(e.Message);	//例外を説明するメッセージを取得
	//例外に関するメッセージを標準出力ではなく、標準エラー出力に出力する
	Console.Error.WriteLine(e);
}
finally {
	全ての例外処理が終わった後に実行する処理
}

//特定の例外を補足する
catch (例外 e) {
	処理
}
//例)
catch (DivideByZeroException e){
	Console.Error.WriteLine(“0では除算できません”);
}
```

## 複数の例外を捕捉
例外ごとに例外ハンドラを記述する

```C#
catch (例外1 e) {
	例外処理
}
catch (例外2 e) {
	例外処理
}
```

基底クラスであるExceptionのハンドラを派生クラスである個別例外のハンドラより前に記述するとコンパイルエラーが発生するので注意

## 意図的に例外を投げる
例外処理が正常に動くか確認できる

```C#
try {
	例外捕捉の対象コード
	throw new 例外クラス(例外オブジェクトの詳細メッセージ);	//メッセージは省略可
}
catch (例外クラス e) {
	例外処理
}
```

## 呼び出し元へ伝わる例外
呼び出したメソッド等の中で発生した例外は、呼び出し元に伝わり、処理される

```C#
//呼び出されたメソッド内の例外ハンドラから呼び出し元に再度例外を投げる(例外の再throw)
catch (Exception e) {
	例外処理
	throw;
}
//投げられた例外は呼び出し元の例外ハンドラで例外処理される
```

## 例外のクラス構成
```
Exception
	|—SystemException
		|—FormatException
		|—IndexOutOfRangeException
		|—ArithmeticException
			|—DivideByZeroException
		|—ArgumentException
			|—ArgumentNullException
```

派生クラスのExceptionは自身以上の基底クラスで捕捉可能