はじめに
スラ!!!本記事を見てくれてありがとうスラ!!!
この記事は駆け出しエンジニア(スライムくん)が優秀なエンジニア(魔王)になるために、
ひたすら学習していく過程の記事だスラ!!!
勉強しながら記事を更新していくスラ!!
本記事の目的は4つだスラ!!
- 学習したことをアウトプットしてレベルアップするためスラ!!
- 楽しみながらアウトプットすることで、モチベーションを高めるスラ!!
- 勉強の姿を見てもらって誰かのモチベーションにもつながればうれしいスラ!!
- 僕が勉強内容をみて誰かの勉強になれば嬉しいスラ!!
ちなみに会話形式のようになっているのは、勉強中の感情をそのまま書くからスラ!!
同じように悩んだ方もきっといるはずだスラ。。。いてほしいスラ。。。
まだまだ駆け出しだけど、たくさん頑張るスラ!!
※本記事はまだ勉強途中なので、どんどこ更新されるスラ。。。
勉強すること
- C#言語の基礎
勉強する背景
Git Hubからクローンしたコードを写経して勉強しようと思ったスラ!!
つまづいたスラ!!とりあえず基礎から学ぶスラ!!
--二日前--
「おらー勉強するスラ!」
「Git Hubログイン!、クローン!」
「ふふふ・・・これで完璧なC#マスターになれるスラ!!!」
:
:
:
「・・・・何も分からないスラ・・・( ^ω^)」
「クラス・・・何だそれスラ・・・むむむ・・・むむむ・・・」
「うわ~ん!どらえも~~~ん!!!」
「ふむふむ・・・何事も基礎からなのかスラ??」
「本屋に行ったら独習C#という本が売っていたスラ!!」
「これで勉強するスラ!!!」
勉強するのに使用した書籍・サイト
というわけで選ばれたのはこの本だスラ!!!
独習C# 著:山田 祥寛 出版社:翔泳社
編集履歴
2021/10/21:新規投稿
2021/10/22:静的メソッドと静的メンバの章を新規作成
#勉強した内容
コンストラクタ
「コンストラクタ・・・これは聞いたことあるスラ!!」
「インスタンス生成時に自動で呼び出されるやつだスラ!!!」
「C++では聞いたことあるけど、C#はどうしたらいいのだスラ???」
「困ったら手を動かすスラ!!!」
:
: 作業中・・・・
:
「できたスラ!!!」
「引数なしコンストラクタ・引数付きコンストラクタを作ったスラ!!!」
「C++と同じだスラね!」
class SelfStudy
{
#region メンバ変数
string firstName;
string lastName;
#endregion
public SelfStudy() {
Console.WriteLine("デフォルトコンストラクタを読んだスラ!!!");
}
public SelfStudy(string firstName) {
Console.WriteLine($"僕は{firstName}スラ!!!");
}
public SelfStudy(string firstName, string lastName) {
Console.WriteLine($"僕の名前は{lastName}{firstName}ですスラ!!!");
}
}
「呼び出してみるスラ!!!」
class Start
{
static void Main(string[] args) {
Console.WriteLine("コンストラクタを呼ぶスラ!!");
SelfStudy selfstudy = new SelfStudy();
Console.WriteLine();
Console.WriteLine("引数1つのコンストラクタを呼ぶスラ!!");
selfstudy = new SelfStudy("firstスラ");
Console.WriteLine();
Console.WriteLine("引数2つのコンストラクタを呼ぶスラ!!");
selfstudy = new SelfStudy("firstスラ", "lastスラ");
Console.ReadLine();
}
}
「ふむふむ・・・」
メソッドのオーバーロードと同じく、引数の規定値を表すためにも、オーバーロードは利用できます。ただし、コンストラクターではメソッド名(引数,...)のような呼び出しはできません。代わりに、コンストラクター初期化子と呼ばれる構文を使ってオーバーロードを呼び出します。(引用 p270)
「ん-よくわからないスラ・・・」
「とりあえず書いてみるスラ!!」
class SelfStudy
{
public SelfStudy(string firstName, string lastName) {
Console.WriteLine($"僕の名前は{lastName}{firstName}ですスラ!!!");
}
public SelfStudy() : this("lastスラ" ,"firstスラ") {
Console.WriteLine("デフォルトコンストラクタを読んだスラ!!!");
}
}
「呼び出すスラ・・・」
static void Main(string[] args) {
Console.WriteLine("コンストラクタを呼ぶスラ!!");
SelfStudy selfstudy = new SelfStudy();
Console.WriteLine();
Console.ReadLine();
}
「引数なしで呼び出したのに、先に引数2つのコンストラクタが呼ばれたスラ!?!?」
「デフォルト引数みたいなものスラかね???」
コンストラクターではメソッド名(引数,...)のような呼び出しはできません。
「下のような感じで呼び出せばよいのではないかスラ???」
「分からないスラ・・・」
「でもとりあえず引数なしでも引数付きを呼び出させることができることが分かったスラ!!!」
selfstudy = new SelfStudy("firstスラ", "lastスラ");
デストラクタ
「これはよく知っているスラ!!!」
「でもこれもC++とは違ったりするのかスラ???」
「悩むよりも動かすスラ!!!」
~SelfStudy() {
Console.WriteLine("デストラクタを呼んだスラ!!!");
Console.ReadLine();
}
static void Main(string[] args) {
CallConstructer();
}
static void CallConstructer() {
Console.WriteLine("コンストラクタを呼ぶスラ!!");
SelfStudy selfstudy = new SelfStudy();
Console.WriteLine();
Console.WriteLine("引数1つのコンストラクタを呼ぶスラ!!");
selfstudy = new SelfStudy("firstスラ");
Console.WriteLine();
Console.WriteLine("引数2つのコンストラクタを呼ぶスラ!!");
selfstudy = new SelfStudy("firstスラ", "lastスラ");
Console.WriteLine();
}
「どうなるかスラ???」
「デストラクタが呼ばれたスラ!!!」
「ふむふむ・・・だけどC#ではあまり使わないスラ???」
「スラ!!!C#にはガーベジコレクションという噂の便利安全機能があるスラか!!!」
「C++のときはdelete忘れてメモリリークしたことがあったスラな・・・」
「それがないのは便利スラ!!でもいつ解放されるか分からないのは怖いスラな・・・」
静的メソッドと静的メンバ
「よく分からないやつらが出てきたスラ・・・」
静的メソッドと静的メンバはクラスで1つだけの存在である。
「ふむふむ・・・これだけ読んでもよく分からないスラな・・・。」
「やってみるスラ!!!」
:
: 作業中・・・
:
「とりあえず静的メンバと静的メソッドを作成したスラ!!!」
#region 定数
static readonly string SLN_FILE_NAME = "SelfStudy.sln";
#endregion
// 静的メソッドを定義
// SelfStudy.slnが置いてあるフルパスを返す
public static string GetSlnPath() {
return Path.GetFullPath(SLN_FILE_NAME);
}
「呼び出すスラ!!!」
「今まではインスタンスを作成してから呼び出していたけど、今回は「クラス名.静的メソッド名」で呼び出せると書いてあったスラ!!!」
「本当に呼べるかスラ???」
class Start
{
static void Main(string[] args) {
// 静的メソッドを呼ぶ
Console.WriteLine("「.sln」のフルパスを表示するスラ!!!");
Console.WriteLine(SelfStudy.GetSlnPath());
}
}
「呼べたスラ!!!」
「newしてインスタンス生成する必要ないスラ!!!」
「ただ実装中に気づいたスラ・・・」
「静的メソッドからは静的メンバしか呼べないスラ!!!」
「静的メソッドから静的でないメンバを参照したらこんな現象になったスラな・・・」
#region 定数
//static readonly string SLN_FILE_NAME = "SelfStudy.sln";
// 上の静的メンバからstaticを消してみる(コンパイルエラー)
readonly string SLN_FILE_NAME = "SelfStudy.sln";
#endregion
// 静的メソッドを定義
public static string GetSlnPath() {
return Path.GetFullPath(SLN_FILE_NAME);
}
「コンパイルエラーになってしまったスラ、、、(´;ω;`)」
「これはどういうことだスラ???」
「まずはstaticとつけた場合、いつメソッドがメモリに展開されるスラかね???」
:
:調べ中・・・
:
「プログラム起動時だったスラ!!!」
「クラスはいつメモリに展開されるスラかね???」
「プログラム上でnewしたときかスラ???」
「よく分からないスラね・・・クラス内に静的メソッドはいるけど、クラスはnewした時点、静的メソッドはプログラム起動時にメモリ確保されるスラ???」
「というこは、静的メソッドはXXクラスの一員ということをプログラムさんはいつ知っているのかスラ???」
「ちょっとここはよく分からなかったスラ・・・」
「ただ、静的メソッドから静的メソッドやメンバしか呼べない理由は分かったスラ!!!」
「静的メソッドはプログラム起動時にメモリ確保するから、このときに静的でないメソッドやメンバはまだメモリにいないスラ!!!」
「それなのに参照してしまうとメモリアクセス違反になるからだと思われるスラ!!」
「ん・・・逆に静的メソッド内でnewしたら呼べるのかスラかね???」
「やってみるスラ!!!」
class SelfStudy
{
#region 定数
static readonly string SLN_FILE_NAME = "SelfStudy.sln";
//readonly string SLN_FILE_NAME = "SelfStudy.sln";
#endregion
#region コンストラクタ
public SelfStudy() {
Console.WriteLine("デフォルトコンストラクタを読んだスラ!!!");
}
#endregion
// 静的メソッドを定義
public static string GetSlnPath() {
// 静的でないメンバを呼んでみる
SelfStudy self_study = new SelfStudy();
self_study.DispConsole();
return Path.GetFullPath(SLN_FILE_NAME);
}
public void DispConsole() {
Console.WriteLine("静的でないメソッドだよ!!!");
}
}
static void Main(string[] args) {
// 静的メソッドを呼ぶ
Console.WriteLine("「.sln」のフルパスを表示するスラ!!!");
Console.WriteLine(SelfStudy.GetSlnPath());
Console.ReadLine();
}
「呼べたスラ!!!」
「ということは静的メソッドは静的でないメソッドのメモリ位置さえ分かれば呼べるスラね!!!」
「これまでのことから静的でないメソッドから静的メソッドは呼べそうだスラ!!」
#region 定数
static readonly string SLN_FILE_NAME = "SelfStudy.sln";
#endregion
// 静的メソッドを定義
public static string GetSlnPath() {
return Path.GetFullPath(SLN_FILE_NAME);
}
public void DispConsole() {
// 静的メソッドを呼び出すスラ
Console.WriteLine(SelfStudy.GetSlnPath());
}
static void Main(string[] args) {
SelfStudy self_study = new SelfStudy();
self_study.DispConsole();
}
「できたスラね!!!」
「ん・・・呼べるのは分かったけど、どんなときにこれを使うのかスラ???」
「シングルトンパターンだスラ???デザインパターンの1つだスラね。」
シングルトンパターン
「ふむふむ・・・シングルトンパターンとは各クラスでインスタンスを1つだけしか作りたくない(共有したい)ときに使うパターンとのことだスラね。」
「確かに、データ管理するクラスとかは、色んなクラスから使用しそうだけど、インスタンスがバラバラだとデータの共有ができなさそうだスラ・・・」
「どうやって実装したらよいスラかね???」
「やってみるスラ!!!」
class SelfStudy
{
#region メンバ変数
// クラスのロード時にインスタンスを保持するスラ
private static SelfStudy m_Instance = new SelfStudy();
public int m_addressTest = 0;
#endregion
#region コンストラクタ
private SelfStudy() {
Console.WriteLine("デフォルトコンストラクタを呼んだスラ!!!");
}
#endregion
public static SelfStudy GetInstance() {
// 保持しているインスタンスを返す
return m_Instance;
}
}
static void Main(string[] args) {
// インスタンスを取得するスラ!
SelfStudy self_study = SelfStudy.GetInstance();
// もう一つインスタンスを取得するスラ!
SelfStudy self_study2 = SelfStudy.GetInstance();
// さらにもう一つインスタンスを取得するスラ!
SelfStudy self_study3 = SelfStudy.GetInstance();
unsafe
{
fixed (int* p = &self_study.m_addressTest)
{
Console.WriteLine($"インスタンス1のアドレスは0x{(int)p}スラ!!!");
}
fixed (int* p2 = &self_study2.m_addressTest)
{
Console.WriteLine($"インスタンス2のアドレスは0x{(int)p2}スラ!!!");
}
fixed (int* p3 = &self_study3.m_addressTest)
{
Console.WriteLine($"インスタンス3のアドレスは0x{(int)p3}スラ!!!");
}
}
}
「できたスラ!!!早速実行してみるスラ!!!」
「3つインスタンスを作成したけど、コンストラクタは1回だけしか呼ばれていないスラ!!!」
「インスタンスのアドレスも同じアドレスを指しているスラ!!!」
勉強中に困ったことリスト
1. Main文はどこのクラスに設定したらよいのかスラ??
どこのクラスでもよいスラ!複数でもよいスラ!!
複数作成した場合は、
ソリューションエクスプローラー内のプロジェクトで右クリック⇒「プロパティ」⇒「アプリケーションタブ」からスタートアップ・オブジェクトを設定すると良いスラ!!
メイン文を以下に記載しておくスラ!
こちらのサイトにお世話になったスラ!!!ありがとうスラ!
https://ufcpp.net/study/csharp/structured/miscentrypoint/
static void Main(string[] args) {
}
2.静的メソッドはXXクラスの一員ということをプログラムさんはいつ知るのか
調べ中スラ!!!誰か教えてほしいスラ!
3.コンソールにインスタンスのアドレスを表示するのはどうしたらよいスラ???
unsafeとfixedステートメントの組み合わせでいけたスラ!!
ただの変数の場合は、unsafeのみでOKスラ!
インスタンスなどガーベジコレクションによって、アドレスが移動してしまう場合は、fixedステートメントでアドレスを固定してあげる必要があるスラ!
以下を参考にしたスラ!
https://atmarkit.itmedia.co.jp/fdotnet/csharp_abc/csharp_abc_021/csharp_abc02.html
でもインスタンスそのもののアドレス表示はやり方がよく分からなかったスラ・・・
どうやらクラスのサイズが分からないからFixedステートメントではできないみたいだけど、他にもやり方があるみたいスラ・・・勉強不足スラ。。。(;´・ω・)
コードを記載しておくスラ!!!
static void Main(string[] args) {
// インスタンスを取得するスラ!
SelfStudy self_study = SelfStudy.GetInstance();
unsafe
{
fixed (int* p = &self_study.m_addressTest)
{
Console.WriteLine($"インスタンスのアドレスは0x{(int)p}スラ!!!");
}
}
}