C#を勉強しなおしてみた(1)
値型と参照型

どもです。

以前からよくC#でデスクトップアプリを作成しているのですが、最近「自分の理解は正しいのだろうか?」と思うことがありました。

そこで、C#の基本を改めて勉強しなおしてみることにしました。この記事では、勉強しなおしのなかで再確認したこと、誤解していたことについて書きます。

1回目の今回は、C#の基本である(と、私が思っている)「値型」と「参照型」について書きます。

1. 値型とは

C#の「型」は、大きく2つに分類できます。それは、「値型」と「参照型」です。この2つの「型」は、そのメモリの管理および参照方法が異なります。「値型」は、変数の領域に値を保持します。

…この説明では何を言っているのかよくわからない、理解しにくいと思うので、絵とコードの両方で説明してみます。

例えば、以下のようなコードでint型の変数を2つ宣言したとします。

int i = 123;
int j = 234;

このとき、2つの変数iおよびjは、メモリ上に以下のように配置されます。(厳密には、この通りではありません。イメージです。)



MSDNでは、これを以下のように表現しています。

値型の変数には、その型のインスタンスが含まれます。

詳しくは、値型の概要を参照してください。

値型では、変数の領域に対して、変数の実際の値(上述の例では、iは123、jは234)が格納されます。ここまでは、当たり前の内容過ぎて特徴でも何でもないように感じると思います。しかし、参照型が絡んでくると、少し理解が変化してきます。

2. 参照型とは

参照型の変数は、データ、即ちオブジェクトへの「参照」を保持します。もう少し詳しく言うと、「メモリ上のオブジェクトへの『アドレス』」を保持します。特徴として、参照型の変数に、別の参照型の変数を代入した場合、実際に代入されるのは「参照」(要は「アドレス」)であるため、代入元と代入先の変数は、同じオブジェクトを指すことになります。

ここでも値型同様、コードと絵で説明してみます。

例えば、Workerクラスについて考えます。あくまで「例」なので、このクラスは「名前」と「番号(いわゆるID)」を持ちます。

public class Worker
{
	public int ID { get; set; }
	public string Name { get; set; }
}

Worker workerA = new Worker(){
	ID = 1,
	Name "hogehoge"
};
Worker workerB = workerA;

このコードを実行した際のメモリ上のデータ構造は、以下のようになっています。



先述の通り、変数workerAとworkerBには「参照」(アドレス)が格納されます。そして、この参照は、Workerオブジェクトの実体の格納先を示します。

変数workerBに変数workerAの値を代入した際にworkerBに格納されるのは、workerAの参照情報、即ちアドレスになります。そのため、先述のコードの代入では、workerBにはworkerAが保持しているアドレスが渡されるのみであり、wokerAが指すオブジェクトはコピーされません。workerAとworkerBが、同じオブジェクトを参照するようになるのみです。

MSDNでは、これを以下のように表現しています。

参照型の変数はデータ (オブジェクト) への参照を格納する

また参照型では、以下の注意が必要です。

ある変数に対する演算によって、他の変数が参照しているオブジェクトが影響を受ける可能性があります。

参照型の変数を扱う際には、同じオブジェクトを参照している変数が無いか、他の変数が変更していないかを意識しながら設計、実装をする必要があります。

3. 値型と参照型

値型と参照型の違いについて書きましたが、ここで以下のような疑問が発生します。

どの型が値型なの?どの型が参照型なの?

この疑問に対する基本的な回答は、

C言語で使用できる型は数値型、それ以外は参照型。

です。

もう少し詳しく言うと、

基本となる型(intとかshort)は、数値型。

class、interface、delegateなどは参照型。また、文字列型(string)も参照型。

です。

なお、「構造体」は「値型」になります。

3. まとめ

今回は、C#を勉強しなおすということで、最も基本である「型」について書いてみました。まとめると、以下のようになります。

  • C#の型は、大きく「値型」と「参照型」の2種類がある。
  • 「値型」変数は、「値」を格納する。
  • 「参照型」変数は、「オブジェクトの参照」即ち「オブジェクトのアドレス」を格納する。
  • 参照型の変数から変数への値は、「オブジェクトの参照」がコピーされ、「オブジェクトはコピーされない」。
    (2つの変数が同じオブジェクトを参照する)
  • 値型は、C言語で使用できる「一般的な」データ型。
  • 参照型は、クラスやオブジェクトといった型。
  • 構造体は「値型」

次回は、「プロパティ」や「フィールド」についてまとめてみます。

ではっ!