手続き型プログラミングとオブジェクト指向プログラミング
クラスの概念が登場する前、C言語のような言語にはクラスが存在しません。C言語に代表される、クラスやオブジェクトを持たないプログラミングスタイルを手続き型プログラミングと呼びます。
手続き型プログラミング:プログラムは一連の命令列であり、実行手順の最適化を核心とします。
クラスが利用できるようになったことで、オブジェクト指向プログラミングを記述できます。
オブジェクト指向プログラミング:プログラムはカプセル化された複数のクラスから構成されます。核心となる考え方はデータとデータを操作する関数を論理的に関連する単位にまとめることで、この単位こそがクラス(class)です。
クラスの定義
クラスは保持するデータ、実行可能なコードを内包するデータ構造であり、大きく2種類のメンバーに分かれます。
- データメンバー(Data Members):オブジェクトの属性データを保管。フィールド(Fields)、定数(Constants)
- 関数メンバー(Function Members):オブジェクトの振る舞いロジックを実装。メソッド、プロパティ、コンストラクタ、デストラクタ、演算子、インデクサ、イベントなど
クラスは論理的に関連するデータと関数をカプセル化した集合で、現実世界または抽象世界の事物を表現するために使用されます。
簡単にまとめると、クラスはデータと関数から成るデータ構造です。クラスからオブジェクトを作成し、オブジェクト経由でデータやメンバーにアクセスできるほか、クラス内部からも直接参照可能です。
クラスの宣言
classキーワードはクラステンプレートを定義するだけで、オブジェクトインスタンスは生成しません。テンプレートはクラス名、クラスメンバー、クラス特性の3つの要素を持ちます。
構文
class クラス名
{
// メンバー宣言(フィールド、メソッドなど順番に制限はない)
}Code language: JavaScript (javascript)
クラス宣言はクラス定義(class definition)と呼ばれることも多いです。
class Program
{
static void Main(string[] args)
{
AddCalculator addCalculator = new AddCalculator();
SubCalculator subCalculator = new SubCalculator();
}
}
class AddCalculator
{
public int A { get; set; }
public int B { get; set; }
public int Add()
{
return A + B;
}
}
class SubCalculator
{
public int A { get; set; }
public int B { get; set; }
public int Subtract()
{
return A - B;
}
}Code language: JavaScript (javascript)
上記の例では2つのクラスを定義し、一方は足し算、もう一方は引き算を処理します。メインプログラムのMain関数内でこれらをインスタンス化して利用しています。
本コンテンツはfoxdevelop.comより提供
クラスの宣言は上から順に記述する必要はありません。後方にクラスを定義し、前方のMain関数から呼び出すことも可能です。クラスは単なる設計図(テンプレート)であり、コードが上から実行されるわけではなく、Main関数から実行が始まり、必要なタイミングで該当するクラスの設計図を参照する仕組みだからです。

クラスメンバー
フィールド(Fields)
フィールドはクラスに属する変数です。組み込み型または自作型を利用可能で、データの読み書きに使用します。
型名 フィールド名;
class MyClass
{
int MyField; // int型フィールド MyField
}Code language: JavaScript (javascript)
C/C++との重要な違い:C#にはグローバル変数が存在しません。すべてのフィールドは型(クラスまたは構造体)内部に記述する必要があります。
フィールドの初期化ルール
(1)暗黙的初期化(値を指定しない場合)
コンパイラが自動的にその型に対応する既定値を割り当てます。型によって既定値は異なります。
int F1; // 既定値 0
string F2; // 既定値 nullCode language: JavaScript (javascript)
下記はC#の型とフィールド既定値の一覧です。これはフィールドに適用されるルールであり、ローカル変数は開発者が明示的に初期化しなければなりません。
基本値型
| データ型 | 既定値 | 説明 |
|---|---|---|
sbyte | 0 | 符号付き8ビット整数 |
byte | 0 | 符号なし8ビット整数 |
short | 0 | 符号付き16ビット整数 |
ushort | 0 | 符号なし16ビット整数 |
int | 0 | 符号付き32ビット整数 |
uint | 0 | 符号なし32ビット整数 |
long | 0L | 符号付き64ビット整数 |
ulong | 0UL | 符号なし64ビット整数 |
float | 0.0f | 単精度浮動小数点数 |
double | 0.0d | 倍精度浮動小数点数 |
decimal | 0.0m | 高精度10進小数 |
char | '\0'(ヌル文字、ASCII 0) | 単一文字 |
bool | false | 論理型 |
列挙型 Enum | 基底整数0に対応する列挙メンバー | 列挙型は整数を基底とし、既定値は0 |
構造体 struct | 各フィールドがそれぞれ既定値を持つ | 自作値型、全体がゼロ初期化される |
参照型
すべての参照型の既定値は統一して null となり、ヒープ上のどのオブジェクトも指していない状態を意味します。
つまりメモリアドレスを保持していない状態です。先ほど紹介したメモリ図を思い出してください。参照型には000001 01010のようなヒープのアドレスが格納されますが、nullの場合は有効なアドレスが一つも保存されていません。
| 型区分 | 例となる型 | 既定値 |
|---|---|---|
| 組み込み参照型 | string、object | null |
自作クラス class | Person Student | null |
| 配列(任意次元) | int[]、string[,] | null |
| デリゲート / イベント | Action、Func、自作delegate | null |
インターフェース interface | 任意のインターフェース変数 | null |
例
string str; // 既定 null
Student jason; // 自作クラス、既定 null
int[] arr; // 配列、既定 null
Action callback; // デリゲート、既定 nullCode language: JavaScript (javascript)
Null許容型(Nullable / T?)
基本データ型の末尾に?を付加すると別の型となり、値なしの状態を表現可能になります。先ほどのint age; は代入しなければ既定値0になりますが、「値自体が存在しない」状態を表したい場合は int? age2; と記述します。age2はNull許容型となり、int? age2 = null; のようにnullを代入できます。
Null許容型はラップされたValueTypeで、既定値が null、「有効な値が存在しない」ことを示します。
| 記述方法 | 既定値 |
|---|---|
int? num | null |
bool? flag | null |
decimal? price | null |
class Test
{
int a; // 自動的に 0
string b; // 自動的に null
bool c; // 自動的に false
}Code language: JavaScript (javascript)
(2)明示的初期化
宣言時に=で値を代入します。代入する値はコンパイル時に確定できる必要があり、ランダムな値やユーザー入力を直接記述することはできません。
int days = 25;
string word = "foxdevelop";Code language: JavaScript (javascript)
(3)同一型の複数フィールド簡略記法
同じ型の変数はコンマで区切って一括宣言可能です。異なる型を混在させることはできません。
int player, blood = 25;
string title, subTitle = "hi welcome to foxdevelop.com";Code language: JavaScript (javascript)
メソッド(Methods)
メソッド定義
メソッドは再利用可能で名前の付いた実行可能なコードブロックで、C++のメンバ関数に相当します。呼び出されると内部コードを実行し、呼び出し元へ処理を戻します。戻り値のあるものと、戻り値のないものに分かれます。
メソッドの4要素
- 戻り値型:戻り値がない場合は
voidを記述 - メソッド名
- 引数リスト:引数なしの場合も
()を省略不可 - メソッド本体:
{}で実行コードを囲む
class Program
{
static void Main(string[] args)
{
Robot robot = new Robot();
robot.SayHello();
}
}
class Robot
{
public void SayHello()
{
Console.WriteLine("Hello everyone");
Console.WriteLine("Welcome to visit foxdevelop.com");
}
}Code language: JavaScript (javascript)
public void SayHello() 先頭のpublicはアクセス修飾子で、この関数をクラス外部から(オブジェクト名.関数名の形式で)呼び出せるようにします。publicを記述しない場合、既定でprivate(プライベート)となり、クラス内部からのみアクセス可能。robotといったオブジェクト経由で外部から呼び出すことはできません。

クラス変数とインスタンスの作成
1. 参照型の基本特性
クラスは参照型に属し、メモリは二つの領域に分かれます。
- スタック(Stack):参照変数(メモリアドレスへのポインタ)を保持
- ヒープ(Heap):オブジェクトの実データを保管
2. 段階的なオブジェクト作成
1 参照変数のみ宣言(スタックメモリだけ確保、ヒープにオブジェクトなし)
Robot robot;
// スタックに参照領域だけ確保、値は未定義。ヒープ上にオブジェクトは存在しない
Code language: JavaScript (javascript)

2 new演算子によるヒープメモリ確保
new 型名();Code language: JavaScript (javascript)
- ヒープにメモリを割り当て、すべてのフィールドに自動で既定値を設定
- ヒープ上のオブジェクト参照アドレスを返し、スタック変数に代入
robot = new Robot();
Code language: JavaScript (javascript)

class Program
{
static void Main(string[] args)
{
Robot robot;
robot = new Robot();
}
}
class Robot
{
void SayHello()
{
Console.WriteLine("Hello everyone");
Console.WriteLine("Welcome to visit foxdevelop.com");
}
}Code language: JavaScript (javascript)
3. 宣言とインスタンス化を一行で記述
Robot robot = new Robot();Code language: JavaScript (javascript)
class Program
{
static void Main(string[] args)
{
Robot robot = new Robot();
}
}Code language: JavaScript (javascript)
クラス定義