##はじめに
C#の基本情報はゴロゴロ転がっていると思いますので、今回も自分用です。
内容は徐々に整理していこう。。
Unityで楽しく遊ぶために、まずはC#の基礎を学ぶことにしました。
自分はpaizaラーニングを利用させて頂いたのですが、本当に勉強して良かった。
最初は「Unityやってるうちに自然に覚えるっしょ」なんて思ってたんですが、
基礎を理解してやるのと、なあなあでやるのでは身に付き方も効率も全然違う!(個人の見解です)
「基本がどれほど大事か わからんのか !!
ダンクが できようが 何だろうが
基本を知らん奴は
試合になったら 何もできやしねーんだ !!」
名言ですね。心に染みます。
ただし、折角勉強したのに内容を忘れてしまっては意味がないので、こちらにメモを残していく事にします。
##覚書
###オブジェクト指向
個人的には初っ端から最難関です。
色々調べさせて頂き、以下のサイトに記述が凄く参考になりました。
https://qiita.com/nrslib/items/73bf176147192c402049
オブジェクト指向は「抽象化」
プログラムを理解しやすくために抽象化を行う。その「抽象化」の技法がオブジェクト指向
あと、シンプルでイメージしやすかったのは下記のサイトです。
https://note.com/tokitky/n/n6e70d7e7a236
オブジェクト指向
変数と関数をひとまとめにしたクラスを作るプログラミングの手法です。
クラスの中の変数は属性と呼ばれます。
クラスの中の関数はメソッドと呼ばれます。
###クラス
クラスはオブジェクトの設計図と考えると解りやすい。
上記の通りクラスは「変数(属性)」と「関数(メソッド)」をひとまとめにしたもの。
属性のイメージは「パラメータ」
例えばネコというクラスを定義した場合、パラメータとしては以下が考えられる。
・名前
・性別
・体重
これが属性のイメージ。
メソッドのイメージは「機能」。
もしネコというクラスを定義した場合、機能は以下が考えらる。
・食べる
・寝る
・遊ぶ
これがメソッドのイメージ。
・クラス: オブジェクトの設計図
・オブジェクト: クラスから作ったもの
####フィールド
フィールドとは、クラスに定義されている変数のこと。
オブジェクトが存在する限り、値が保持される。
オブジェクト志向のカプセル化を実現するために、フィールドはプライベートにすることが多い。
####thisキーワード
クラスの現在のインスタンスを参照するときに、付け加えるキーワード。
要はクラスではなく、自分自身(インスタンス)の、という意味らしい。
class Player
{
private string name;
public Player(string name)
{
this.name = name;
}
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
####プロパティ
プロパティとは、プライベートフィールドの読み書きおよび計算をする際に利用する機能。
C#では慣例的にアルファベットの先頭文字を大文字にしている。
プライベートフィールドは、クラスの外からアクセスできないため、そのフィールドにアクセスするパブリックのメソッドやプロパティが必要となる。
{
get
{
return 値を取得するフィールドの変数名;
}
set
{
値を代入するフィールドの変数名 = value;
}
}
・省略形
プロパティがgetとsetのみであれば、以下の形に省略できる
※外部からプロパティを変更されたくない場合は、setをプライベートにする。
public int Count { get; private set; }
//get (オブジェクト名.プロパティ名)
Item.Count
//set (オブジェクト名.プロパティ名 = value)
Item.Count = 1;
####コンストラクタ
コンストラクタとは、名前がその型の名前(クラスの名前)と同じメソッドのこと。
クラスからオブジェクトを作成するたびに呼び出されるメソッド。
(クラスからオブジェクトを呼び出すときに最初に呼び出されるメソッド)
####デストラクタ
コンストラクタとは逆に、オブジェクトが消滅する際に呼び出されるメソッド。
####継承
クラスを引き継いで、新しいクラスを定義できる
・クラスの継承元 → 基底クラス
・クラスの継承先 → 派生クラス
野球選手という基底クラスから、選手兼監督という派生クラスを定義するイメージ
野球選手の機能を持ちながら、異なる機能も定義できる。
属性の定義がある場合、コンストラクタが必要
基底クラスから派生したクラスは、基底クラスの型となっている配列の要素に追加することが出来る
メソッドのオーバーライドが出来る。(後述)
クラス定義時に <: 基底クラス> を付与する事で派生クラスとして定義。
下記の例ではBoxの派生クラスとしてJewelryBoxを定義している。
class Box
{
private string Item { get; private set; }
public Box(string item)
{
Item = item;
}
}
class JewelryBox : Box //この<: Box>で、Boxの派生クラスであることを定義している
{
public JewelryBox(string item) : base(item) //コンストラクタはBoxと同じ内容
{
}
public void Look()
{
Console.WriteLine("宝箱はキラキラと輝いている。");
}
}
上記の場合、派生クラスJewelryBoxには新しくLookというメソッドが追加されている。
####メソッドのオーバーライド
メソッドにvirtualキーワードをつけて定義すると、そのメソッドは仮想メソッドとなる。
オーバーライドできるメソッドは仮想メソッドであり、非仮想メソッドはオーバーライドできない。
→基底クラスのメソッドは仮想メソッドにする(virtual)
→派生クラスのメソッドにoverrideを付けて定義する
class Box
{
public virtual void Open()
{
Console.WriteLine("宝箱を開いた。");
}
}
class CloseBox : Box
{
public override void Open()
{
Console.WriteLine("宝箱には鍵がかかっていた。");
}
}
####メソッドのオーバーロード
メソッドのオーバーロードを使うと同じメソッド名で引数の数やデータ型が異なるメソッドを複数定義することができる。
→同じ名前のメソッドを引数の有無、数、データ型で分岐させるイメージ
###オブジェクト
・変数とメソッドをセットになっている
・クラス(設計図)からオブジェクトを作る
・クラスを引き継いで、新しいクラスを定義できる
オブジェクトを作る
→生成したオブジェクトは変数に割り当てる
オブジェクトのメソッドを呼び出し
→オブジェクト名.メソッド名(引数)
文字列や配列もオブジェクトになっている
→stringクラスのオブジェクト
###名前空間(Namespace)
クラスを整理するために使われる概念。
個人的なイメージはクラスのフォルダ分け。フォルダ名=名前空間。
標準ライブラリで言うと
・Systemという名前空間にArrayやConsoleクラスなどを定義(一般的なクラス)
・System.IOという名前空間にFileやPathクラスなどを定義(ファイルやデータのクラス)
処理の呼び出し
名前空間.クラス.メソッド(引数)
####using キーワード
スクリプトのはじめに書いているアレ。
あらかじめusingで名前空間を指定しておくと、メソッドを呼び出す際の名前空間を省略できる
using System
//System.Console.WriteLine(); //usingでSystemの名前空間を指定しているので、Systemが省略可能。
Console.WriteLine();
###staticの役割
staticがついた変数やメソッドは、全てのオブジェクトで共通して利用できる。
また、オブジェクトを作らなくてもアクセスできる。
→staticのメソッドを呼び出すときは、メソッド名の前にクラス名を指定する。
クラス名.メソッド名(引数);
###メソッド
メソッドとは、一連の処理を一つにまとめて繰り返し使えるようにしたかたまり。
メソッド名の最初は大文字(C#の慣例)
メソッド内の記述↓
・ブロック{}で囲った範囲(メソッドブロック)→IFブロック、forブロックなど
###スコープ
変数の有効範囲
メソッド内のみ(ローカル変数)
C#では、ブロックの中で宣言されたローカル変数は、ブロックの外では利用できない。
###引数
####引数のデフォルト値
引数にイコールで値を与えるとデフォルト値となり、メソッドで引数を省略した場合に利用できる。
C#では、デフォルト値を設定したい引数は、デフォルト値を設定しない引数の後に定義しなければならない。
public void Look(string name = "村人")
####名前付き引数
メソッドの引数にラベルを付ける機能。
引数にラベルを付けると、変数に対応する値を指定できる。
※任意の引数を省略出来るようになる(引数にデフォルト値がある場合) 可読性も良く、引数の順番を変えることもできる
SayHello(greeting: "おはようございます");
public static void SayHello(string target = "みなさん", string greeting = "Hello")
####可変長引数
どのくらいの引数が来るか分からない場合に使用
paramsキーワードの後に、配列を指定すると可変長引数にすることができる。
Introduce("勇者", "戦士", "魔法使い");
public static void Introduce(params string[] people)
{
foreach (string name in people)
{
Console.WriteLine("私は" + name + "です");
}
}
###アクセス修飾子
アクセスの制限をコントロールするもの。
オブジェクトのフィールド内はprivateとしておき、メソッドで呼び出すといった制御が推奨されている。
例えば、「private int number = 1;」というnumber変数があった場合、このnumber変数は宣言されているクラス内のみで使用できる。
※省略するとprivateになる(ただし、クラスは省略するとinternalになる)
internal修飾子は、同じプロジェクト内での参照が許されるアクセス修飾子。
正確には、同じアセンブリ内の任意のコードから参照が許されるアクセス修飾子。
アセンブリとは、.NETで使用されている単位のことです。
アクセシビリティ | 効果 |
---|---|
public | どこからでもアクセス可能 |
private | そのクラスの内部からアクセス可能 |
protected | そのクラスと継承したクラスの内部からアクセス可能 |
internal | 同じアセンブリ内の任意のコードからアクセス可能、別のアセンブリからはアクセス不可 |
protected internal | 同じアセンブリ内の任意のコード、または別のアセンブリ内の任意の派生クラスからアクセス可能 |
private protected | 基底クラスアセンブリ内の同じクラスまたは派生クラスのコードがアクセス可能 |
###構造体
構造体はクラスのような、データ型の1つ。
クラスはオブジェクトの作成後に変更されることを前提としたデータで使用され、
構造体は作成後に変更されないことを前提としたデータで使用され、小規模なデータ構造で使用される。
###データ型
下記のサイトが物凄く解りやすい。型変換についても記載あり。(本当にありがとうございます)
https://www.sejuku.net/blog/103582
###デリゲート
下記のサイトを参考に勉強させて頂きました。
C#のデリゲート (delegate) って何?
https://qiita.com/rawr/items/11790e9ea08a29d028a4
データ型(参照型)の一つで「メソッド(関数)を受け取る」ことが出来る。
→「変数の中に関数を代入するための型」というイメージ
→処理を他のメソッドに委譲(丸投げ)する
デリゲートで宣言した変数には、複数の関数を代入することが出来る
複数の関数を代入したデリゲートを「マルチキャストデリゲート」と呼ぶ
(「+=」「-=」で関数を追加したり外したり出来る)
デリゲートのメリットは?(予想)
・コードがシンプルになる(メンテナンス性も良くなりそう)
・メソッドを汎用化できる
「メソッドの引数にメソッドを渡せる」というのを上手く使えば色々出来そう。。?
【デリゲートの宣言】
delegate 戻り値の型 デリゲート名 (引数の型 引数);
↑delegate キーワードとやらを付ける
【デリゲートの実行】
// デリゲート型の変数を宣言
public delegate void Test();
static void Main()
{
// デリゲートにメソッドの代入
Test hoge = Hoge;
// デリゲートを実行
hoge();
}
// デリゲートに代入するメソッド
static void Hoge() {
Console.WriteLine("hoge");
}
デリゲートの主な利用用途はイベントハンドラやコールバック。
【イベントハンドラ】
「クリック」や「キー入力」のようなイベントに応じて、対応する処理を行う仕組み。
【コールバック】
関数を実行している途中で別の関数を実行させる仕組み。
####定義済みデリゲート
予め定義された”Action”と”Func”というデリゲートがある。
→自分で宣言しなくても使える
この2つは若干用途が異なる。
”Action”:戻り値なし
”Func”:戻り値あり
※様々な型に対応している。
####匿名メソッド
デリゲート変数の中に、メソッドの定義をそのまま入れちゃったもの
メソッドそのものに名前が無いので匿名メソッドと呼ばれる
→デリゲートを更に使いやすく出来る
デリゲートのちょっと面倒な所。
・一回しか使わないのに、わざわざメソッドを作るのメンドイ
・メソッドが遠く離れた行で作成されてたりすると凄く解りづらい(可読性わるい)
これを解決できる。
// デリゲート型の変数を宣言
public delegate void Test();
static void Main()
{
// デリゲートにメソッドの定義を代入
Test hoge = delegate(){Console.WriteLine("hoge")};
// デリゲートを実行
hoge();
}
更に、メソッドの引数として匿名メソッドを書き込むこともできる
var test = list.Select(
delegate(int n)
{
return 0 < n;
};
この時、メソッドを受け取る側の引数は定義済みデリゲート”Action”と”Func”を使うと良いらしい
→メソッドを表す型が無いからとのこと。
ちなみに匿名メソッドで生成するデリゲートの引数は型推論が出来る(型を省略できる)
####ラムダ式
匿名メソッドを簡略化したもの(色々省略したもの)
【ラムダ式の記法】
// #0 匿名メソッド
var test = list.Select(delegate(int n){ return 0 < n });
// #1 delegateキーワードを演算子=>に置き換え(位置がちょっと変わる)
var test = list.Select((int n) => { return 0 < n });
// #2 引数の型推論が出来るので、型を省略
var test = list.Select((n) => { return 0 < n });
// #3 中身が1行なら[]とreturnは省略
var test = list.Select((n) => 0 < n);
// #4 引数が一つなら()も省略(0はダメらしい)
var test = list.Select(n => 0 < n);
###例外処理
実行時に発生する問題にプログラムを対応させる。
try: あらかじめコードを指定して、プログラム実行時に、処理の問題を検出する。
catch: 問題を検出したとき、どのように対応するか記述しておく。
throws: 対応を記述していない場合、メソッドの呼び出し元に対応を任せる。
throwで意図的に例外を投げられる。引数でメッセージを指定可能。
throw new ArgumentNullException();
例外の再スロー : メソッドの中で処理中に例外が発生した場合、呼び出し元へその例外が伝わる
throw;
####例外のクラス構成
ここでは一部のみ記載。Exceptionが親オブジェクトになる。
【Exception】(基底クラス)
例外の詳細を格納したオブジェクト
C#では、親の例外が先になっているとコンパイルエラーになる
【DivideByZeroException】(派生クラス)
ゼロ除算で発生する例外
【FormatException】(派生クラス)
引数の形式が無効な場合に発生する例外
【ArgumentNullException】(派生クラス)
nullを引数として受け付けないメソッドに、nullを渡した場合に発生する例外
【IndexOutOfRangeException】(派生クラス)
範囲外のインデックスを使用して、配列やコレクションの要素にアクセスしようとしたときに発生する例外