C# ユーザー定義データ型とクラスの作成を初心者が説明してみる


今回はC#のデータ型ということで、前回の記事の続きとなります。
前回は「標準定義データ型」と「ユーザー定義データ型」の2種類のうちの「標準定義データ型」について紹介しました。
今回も一緒に勉強しましょう!

ユーザー定義データ型とは

まずはこちらのリストをご覧ください。

データ型 型の種類
構造体 値型
列挙体 値型
リスト 参照型
レコード 参照型
配列 参照型
クラス 参照型
デリゲート 参照型
インターフェイス 参照型

なんだか聞き慣れない言葉がたくさんありますね。
中には他の言語でも出てくるデータ型もあります。
「ユーザー定義データ型」という言葉の意味としては、そのまま受け取っていいものかと思います。
ユーザーが自分で定義できるデータ型ということですね。
一方、標準データ定義型についてはユーザーではなく、「言語で決められているデータ型」ということになります。
じゃあこの値型と参照型って一体何なの?ってところからいきましょう。
両者共通して、メモリがどーのこーのってお話が出てくるので難しくなるかも…

値型のデータ

メモリのスタックと呼ばれる領域を使う

前回の記事でもご紹介した標準定義データ型の値型の変数(int型やdecimal型など)はメモリのスタックと呼ばれる領域を使用します。
このスタックのデータは「後入れ先出し」方式(メモリの管理方法)でデータがメモリに格納されます。

独自の値を持つ

int x; //int型(値型)の変数xを宣言(生成)
x = 100; //xに100を代入
Console.WriteLine(x) // 出力は100

int y; //int型(値型)の変数yを宣言(生成)
y = x; //yにxの値(100)を代入
Console.WriteLine(y); //出力は100

y = 10; //yに10を代入
Console.WriteLine(y); //出力は10

さて、これで何がわかるか。
後入れ先出しのお話をチラッとしましたが、これです。
鍵となるコードはこちら。

int y; //int型(値型)の変数yを宣言(生成)
y = x; //yにxの値(100)を代入
Console.WriteLine(y); //出力は100

y = 10; //yに10を代入
Console.WriteLine(y); //出力は10

yの値に注目してください。
最初にyの値には100が格納(代入)されていたのに、後から10が格納されています。
僕はこれが値型の特徴で、「上書きができる」という認識でいます。
ただし、スコープ(変数の適用範囲)などでややこしくなる気はしています笑
スコープについては別記事にてご紹介の予定です。(そうでもしないと記事が長くなって収拾がつかない)

では次に参照型について見ていきましょう。

参照型

参照型データはメモリ領域への「参照情報」が格納される

値型についてはなんとなく理解できるのではないかと思います。
では、「参照型データはメモリ領域への「参照情報」が格納される」ということについて。
どういうことかというと、値型とは違って、「メモリに格納された内容そのものをコピー」するということかなと思います。
値型とは違って、「インスタンスを生成した時にメモリに格納された内容を使って変数を生成する」という解釈で合ってますかね?
いやもう書いている自分がうまく伝えられていない気がしてならない笑
インスタンスということは、つまりクラスの作成が必要ということになります。
オブジェクト指向型プログラミング言語って大変ですね〜

とりあえずまずはコードから!
意外とコードから理解できることってありません?笑

Value x; //Value型の変数xを宣言
x = new Value(); //インスタンスを生成し、参照情報をxに代入
x.value = 10; //xが参照するインスタンスのvalueフィールドに10を代入

Value y; //Value型の変数yを宣言
y = new Value(); //インスタンスを生成し、参照情報をyに代入
y = x; //xの参照情報をyに代入
y.value = 20; //

Console.WriteLine(x.value); //出力は20
Console.WriteLine(y.value); //出力は20

class Value //Valueクラスを定義
{
    public int value; //int型の「フィールド」valueを宣言
}

はい、こんな感じです。
多分よくわからん!という方が大半かと思います。
僕も説明の仕方がわからん!です。

値型との決定的な違い

まずはこの辺からですかね…
クラスというものが出てきました。
そしてnewというキーワード。
これがインスタンスの生成です。

Value x; //Value型の変数xを宣言
x = new Value(); //インスタンスを生成し、参照情報をxに代入
x.value = 10; //xが参照するインスタンスのvalueフィールドに10を代入

class Value //Valueクラスを定義
{
    public int value; //int型の「フィールド」valueを宣言
}

まず大前提として、クラスの定義は一番下、ステートメントは上から順に書いてください。
クラスを上に書くとエラーが起こります。
エディターでインテリセンス(コード補完)機能を利用している方はクラスを先に書いて、その上にメソッドを書くとインテリセンス機能が利用できます。

クラスについて

クラス
class Value //Valueクラスを定義
{
    public int value; //int型の「フィールド」valueを宣言
}

参照型のデータを扱いやすくするためのものだと思ってください。僕はそう思ってます。まぁそもそもこれがないとダメ(参照型のデータにならない)なんですけどね。
クラス内で宣言されているvalue(頭文字は小文字だよ。クラス名の頭文字は大文字だよ)は変数と思ったら大間違い。ってほどでもないのですが、フィールドと呼ばれる「設定値」という感じですかね。
この辺は定型文のような感じで使っているのでちゃんと理解してないですすみません。
クラスに関してはこれからも深掘していきます。

クラスのインスタンス

Value x; //Value型の変数xを宣言
x = new Value(); //インスタンスを生成し、参照情報をxに代入
x.value = 10; //xが参照するインスタンスのvalueフィールドに10を代入

先述の内容はクラスのもの(大したこと説明できてないですが)なので、次はインスタンスについてですね。
上から順に、
・Valueクラスを利用してxを宣言(生成)しますよ〜
・Valueクラスのインスタンスを生成して、その参照情報をxに代入しますよ〜
・x(Valueクラス)の参照情報であるvalueフィールドに10を代入しますよ〜
といった感じです。
訳がわかりませんね!
正直合ってるかどうかもわかりません!(毎度言ってますが、一応僕自身の備忘録的なものなので悪しからず)

Value x; //Value型の変数xを宣言

まず、一行目のValueですが、int型やstring型と同じようなものと思ってください。
コード内のコメントにはValue型と書いてありますが、そんな感じです。
クラスを利用する場合、"クラス名 変数名;"で変数を宣言できます。

x = new Value(); //インスタンスを生成し、参照情報をxに代入

続いて、二行目ですが、newキーワードはインスタンスを生成しますよ〜という命令文です。
これはValue型のxという変数を宣言したのだからお前さん(Valueクラス)の情報よこせ!ということです。横暴ですね。
コード内のコメントには「参照情報」とあります。
この参照情報は上記のクラス定義のコードに書いてあるint型のvalueになります。
クラス内に別の変数(フィールド)を宣言している場合は、それも参照情報のひとつになります。

x.value = 10; //xが参照するインスタンスのvalueフィールドに10を代入

最後に三行目ですが、「Valueクラスを利用したxという変数の参照情報であるvalueという変数(フィールド)に10を代入する」ということです。
長ったらしくてわかりづらいですが、頑張って噛み砕いてください。
今の僕にはこの説明が限界です…笑
"変数.クラスのフィールド名"で参照情報の操作ができます。

なぜ出力した値は別の変数なのに同じ値なのか問題

Console.WriteLine(x.value); //出力は20
Console.WriteLine(y.value); //出力は20

参照した先のフィールドは値を上書きされた場合、別の変数でも同じ値になります。
変数名1.フィールド名1 = 変数名2.フィールド名1
といったように、参照型データの特性上、データは共有されるものとなります。
この共有というものですが、何が共有されているかというと、変数の値ではなくメモリのアドレスを共有しているんですね。
Aさんが東京ディズニーランドという場所を訪れ、Bさんが東京ディズニーランドという場所を訪れても、東京ディズニーランドは東京ディズニーランドです。
東京ディズニーランドに新しいアトラクションができた場合、AさんとBさんのどちらが訪れても新しいアトラクションがあります。Cさんが訪れても同様です。
っていう解釈をしています。(この記事を書きながら思いつきましたすみません)
これが「なぜ出力した値は別の変数なのに同じ値なのか問題」の答えだと思っています。



てな感じで「参照型データ」の説明は以上になります。
この記事で書ききれない内容がたっぷりあるので、データ型の記事はまだまだ続く予感…
メモリについての内容もそのうち投稿しようと思います。

最後に

記事を書きながら自分で噛み砕いて理解しようと頑張っているのですが、伝わっているかどうかの前に自分が正しく理解できているかというのが不安ですね(毎度言ってますね、これからも言い続ける思います。)
ただ、理解度は少しでも深まっているのかなとは思います。
記事を書く時頭フル回転してます。
てか、ちゃんと理解してから書くべきなのか?

いやそもそも伝える以前の問題でこれ備忘録だからね。
自分が振り返る時にQiitaを読んで思い出すためのものだからね。
しかもコメントでご教授いただけるなんて贅沢だなぁと。
学びや気付きって、便利な世の中であるからこそ自分が受けられる恩恵だなぁ。

というわけで今回はここまで!
初心者の方、一緒に勉強しましょう!
プロフィール欄からTwitterのフォローよろしく!笑