C#の初期化を完全解説|変数・配列・List・クラス・プロパティの書き方と注意点

はじめに

C#の初期化は、変数・配列・List・クラス・プロパティを安全に使うための基本です。初期化を正しく理解していないと、「未割り当てのローカル変数を使用しました」「NullReferenceException」「プロパティの初期化漏れ」などのエラーにつながります。

この記事では、C#の初期化について、基本的な変数の初期化から、配列、List、クラス、オブジェクト初期化子、プロパティ、initrequireddefaultnullの扱いまで、実務で使える形で整理します。

C#では、変数の種類や宣言場所によって初期化ルールが異なります。特にローカル変数は、値を読み取る前に必ず明示的に初期化されている必要があります。一方、フィールドや配列要素などは型ごとのデフォルト値で自動的に初期化されます。Microsoft Learn+1

1. C#の初期化とは?代入・宣言・インスタンス化との違い

1-1. 初期化の基本:値を使う前に状態を決めること

C#における初期化とは、変数やオブジェクトを使い始める前に、最初の値や状態を設定することです。

C#
int count = 0;
string name = "Tanaka";
bool isActive = true;

この例では、countnameisActiveに最初の値を設定しています。これが初期化です。

初期化の目的は、値が不明な状態のまま処理を進めないことです。特にC#では、型安全性が重視されるため、変数がどのような値を持つのかを明確にしてから使うことが重要です。

1-2. 宣言・代入・初期化・インスタンス化の違い

C#では、「宣言」「代入」「初期化」「インスタンス化」が似た場面で使われますが、意味は異なります。

C#
int x;        // 宣言
x = 10; // 代入
int y = 20; // 宣言と初期化
var user = new User(); // インスタンス化と初期化

宣言は、変数名と型をコンパイラに知らせることです。代入は、すでに存在する変数に値を入れることです。初期化は、変数やオブジェクトを使い始めるために最初の値を設定することです。インスタンス化は、newを使ってクラスや構造体の実体を作ることです。

つまり、初期化は「最初の代入」と考えると理解しやすいです。

1-3. 初期化しない場合のデフォルト値

C#では、フィールド、配列要素、静的変数などは、型ごとのデフォルト値で自動的に初期化されます。

代表的なデフォルト値は次のとおりです。

デフォルト値
int0
double0.0
boolfalse
char'\0'
stringnull
参照型null
int?などのnullable値型null相当

C#の組み込み型には標準のデフォルト値が定義されており、defaultキーワードでも取得できます。Microsoft Learn

C#
int number = default;      // 0
bool flag = default; // false
string text = default; // null

ただし、ローカル変数は自動的に使える状態になるわけではありません。

C#
void Sample()
{
int x;
// Console.WriteLine(x); // コンパイルエラー
}

ローカル変数は、値を読み取る前に明示的に初期化する必要があります。

1-4. ローカル変数とフィールドで初期化ルールが違う理由

ローカル変数とフィールドでは、初期化のルールが異なります。

C#
class Sample
{
private int count; // 自動的に0で初期化される

void Method()
{
int localCount;
// Console.WriteLine(localCount); // エラー
}
}

フィールドはオブジェクトが作成されるタイミングで、型のデフォルト値に初期化されます。一方、ローカル変数はメソッド内の一時的な変数であり、C#では「確実に代入されている」ことがコンパイル時に求められます。C#仕様では、変数の値を取得する前に definite assignment、つまり確実な割り当てが必要とされています。Microsoft Learn

この仕組みにより、初期化漏れによる予期しない動作を防げます。

1-5. C#で初期化が重要になる主な場面

C#で初期化が重要になる場面は多くあります。

変数を使う前、配列やListを作るとき、クラスのインスタンスを作成するとき、プロパティに初期値を設定するとき、DTOや設定クラスを作るとき、テストデータを準備するときなどです。

特に実務では、次のようなコードで初期化が頻繁に登場します。

C#
var users = new List<User>();

var options = new AppOptions
{
TimeoutSeconds = 30,
EnableLogging = true
};

var user = new User("Sato")
{
Age = 30
};

初期化の書き方を整理しておくと、コードの安全性と可読性が上がります。

2. C#の変数を初期化する方法

2-1. 基本型の初期化:int・double・bool・char

C#の基本型は、宣言と同時に値を入れるのが一般的です。

C#
int age = 30;
double price = 1980.5;
bool isEnabled = true;
char grade = 'A';

最初の値が決まっていない場合でも、意味のある初期値を設定しておくと安全です。

C#
int total = 0;
double average = 0.0;
bool hasError = false;

数値の集計であれば0、判定フラグであればfalseなど、用途に合う初期値を選びます。

2-2. string型の初期化:空文字・null・文字列リテラル

stringは参照型なので、デフォルト値はnullです。ただし、実務ではnullよりも空文字で初期化した方が扱いやすい場面があります。

C#
string name = "Yamada";
string empty1 = "";
string empty2 = string.Empty;
string? nullableText = null;

空文字は「値はあるが文字数が0」という状態です。nullは「値そのものが存在しない」という状態です。

C#
string name = string.Empty; // 未入力を表す
string? memo = null; // メモが存在しない可能性を表す

フォーム入力や表示用テキストでは空文字、取得できない可能性がある値ではstring?nullを使うと意図が明確になります。

2-3. varを使った暗黙的な型推論での初期化

varを使うと、右辺から型を推論できます。

C#
var count = 10;          // int
var name = "Suzuki"; // string
var prices = new List<int>(); // List<int>

varは型を省略しているだけで、動的型付けではありません。コンパイル時には型が決まります。

ただし、varは初期化式が必要です。

C#
// var x;       // エラー
// var y = null; // 型を推論できないためエラー

型が分かりにくくなる場合は、明示的な型を書く方が読みやすくなります。

C#
Dictionary<string, int> scores = new();

2-4. const・readonly変数の初期化

constはコンパイル時定数です。宣言時に必ず初期化する必要があります。

C#
const int MaxCount = 100;
const string AppName = "SampleApp";

readonlyは、宣言時またはコンストラクター内で初期化できます。

C#
class UserService
{
private readonly string _connectionString;

public UserService(string connectionString)
{
_connectionString = connectionString;
}
}

constは完全に固定された値に使い、readonlyはインスタンス生成時に決まる値に使います。

2-5. nullable型の初期化とnull許容参照型の注意点

値型に?を付けると、nullを許容できます。

C#
int? age = null;
DateTime? completedAt = null;

参照型でも、C#のnull許容参照型を有効にしている場合は、stringstring?を区別できます。

C#
string name = "Sato";     // nullを想定しない
string? nickname = null; // nullを許容する

null許容参照型は、実行時の動作を変える機能ではなく、コンパイル時にnullの可能性を警告するための機能です。Microsoft Learn

C#
string? text = GetText();

if (text is not null)
{
Console.WriteLine(text.Length);
}

nullの可能性がある値は、使用前にチェックするのが基本です。

2-6. 変数初期化でよくあるエラーと対処法

よくあるエラーは、ローカル変数を初期化せずに使うケースです。

C#
int result;

if (DateTime.Now.Hour < 12)
{
result = 1;
}

// Console.WriteLine(result); // resultが未代入の可能性がある

この場合は、最初に初期値を入れるか、すべての分岐で代入します。

C#
int result = 0;

if (DateTime.Now.Hour < 12)
{
result = 1;
}

Console.WriteLine(result);

または、elseを使って必ず値が入るようにします。

C#
int result;

if (DateTime.Now.Hour < 12)
{
result = 1;
}
else
{
result = 2;
}

3. C#の配列を初期化する方法

3-1. 要素数を指定して配列を初期化する

配列は、同じ型の要素を固定長で管理するための仕組みです。C#の配列は、要素の型を指定して宣言します。Microsoft Learn

C#
int[] numbers = new int[3];

このコードでは、int型の要素を3つ持つ配列を作成しています。各要素はintのデフォルト値である0になります。

C#
Console.WriteLine(numbers[0]); // 0

3-2. 初期値を指定して配列を作成する

配列は、作成時に要素を指定して初期化できます。

C#
int[] numbers = new int[] { 10, 20, 30 };
string[] names = new string[] { "Sato", "Suzuki", "Tanaka" };

要素数は初期値の数から決まるため、明示的に長さを書く必要はありません。

3-3. newを省略した配列初期化の書き方

宣言と同時に初期化する場合、newを省略できます。

C#
int[] numbers = { 10, 20, 30 };
string[] names = { "A", "B", "C" };

短く書けますが、後から代入する場合はnewが必要です。

C#
int[] numbers;
numbers = new int[] { 10, 20, 30 };

3-4. 空配列を初期化する方法

空の配列を作りたい場合は、Array.Empty<T>()がよく使われます。

C#
int[] numbers = Array.Empty<int>();
string[] names = Array.Empty<string>();

次のようにも書けます。

C#
int[] numbers = new int[0];

ただし、空配列を何度も作る場合は、Array.Empty<T>()の方が意図が明確です。

3-5. 多次元配列・ジャグ配列の初期化

多次元配列は、行と列のような構造を表すときに使います。

C#
int[,] matrix = new int[2, 3];

int[,] initializedMatrix =
{
{ 1, 2, 3 },
{ 4, 5, 6 }
};

ジャグ配列は、配列の中に配列を持つ構造です。

C#
int[][] jagged = new int[3][];

jagged[0] = new int[] { 1, 2 };
jagged[1] = new int[] { 3, 4, 5 };
jagged[2] = new int[] { 6 };

ジャグ配列は、行ごとに要素数が異なる場合に便利です。

3-6. 配列の各要素に入るデフォルト値

配列を要素数だけ指定して作ると、各要素には型のデフォルト値が入ります。

C#
int[] numbers = new int[3];       // 0, 0, 0
bool[] flags = new bool[3]; // false, false, false
string[] names = new string[3]; // null, null, null

参照型の配列では、各要素が自動的にインスタンス化されるわけではありません。

C#
User[] users = new User[3];

// users[0].Name = "Sato"; // users[0]がnullなので例外
users[0] = new User();
users[0].Name = "Sato";

配列そのものを初期化しても、参照型の各要素は別途初期化が必要です。

3-7. 配列初期化でよくあるミス

配列でよくあるミスは、長さを超えたインデックスにアクセスすることです。

C#
int[] numbers = new int[3];

// numbers[3] = 40; // エラー。最後のインデックスは2

配列のインデックスは0から始まるため、長さが3なら使えるインデックスは012です。

また、配列は固定長です。後から要素数を増やしたい場合は、List<T>を使う方が自然です。

4. C#のListを初期化する方法

4-1. List<T>の基本的な初期化

List<T>は、要素数を後から増減できるコレクションです。

C#
List<int> numbers = new List<int>();

C# 9以降では、左辺から型が分かる場合にnew()と書けます。

C#
List<int> numbers = new();

List<T>を使うには、通常は次の名前空間を使います。

C#
using System.Collections.Generic;

4-2. 要素を指定してListを初期化する

最初から要素を入れてListを作る場合は、次のように書けます。

C#
List<string> names = new List<string>
{
"Sato",
"Suzuki",
"Tanaka"
};

List<int>でも同じです。

C#
List<int> scores = new List<int> { 80, 90, 100 };

4-3. 空のListを作成する書き方

空のListを作る場合は、次の書き方が基本です。

C#
var users = new List<User>();

後から要素を追加します。

C#
users.Add(new User { Name = "Sato" });
users.Add(new User { Name = "Suzuki" });

空の配列と違い、Listは後からAddで要素を追加できます。

4-4. コレクション初期化子を使った書き方

コレクション初期化子を使うと、作成と同時に要素を追加できます。Microsoftのドキュメントでも、コレクション初期化子は初期値を持つコレクションを簡潔に作成する構文として説明されています。Microsoft Learn

C#
var numbers = new List<int>
{
1,
2,
3
};

内部的には、各要素に対してAddが呼び出されるイメージです。

4-5. 配列からListを初期化する方法

配列をもとにListを作ることもできます。

C#
int[] array = { 1, 2, 3 };

List<int> list = new List<int>(array);

LINQのToList()を使う方法もあります。

C#
using System.Linq;

int[] array = { 1, 2, 3 };
List<int> list = array.ToList();

既存の配列を可変長のコレクションとして扱いたい場合に便利です。

4-6. オブジェクトのListを初期化する方法

オブジェクトのListでは、オブジェクト初期化子と組み合わせる書き方がよく使われます。

C#
var users = new List<User>
{
new User { Id = 1, Name = "Sato" },
new User { Id = 2, Name = "Suzuki" },
new User { Id = 3, Name = "Tanaka" }
};

DTOやテストデータの準備で頻繁に使われるパターンです。

4-7. List初期化時の容量指定とパフォーマンス

大量の要素を追加することが分かっている場合は、容量を指定して初期化できます。

C#
var items = new List<string>(1000);

これは要素数を1000にするわけではなく、内部配列の初期容量を1000にするという意味です。

C#
Console.WriteLine(items.Count); // 0

容量を指定すると、要素追加時の内部的な再確保を減らせる場合があります。

4-8. 配列とListの初期化の使い分け

配列は、要素数が固定で変わらない場合に向いています。

C#
string[] weekdays = { "Mon", "Tue", "Wed", "Thu", "Fri" };

Listは、要素数が増減する場合に向いています。

C#
var tasks = new List<string>();
tasks.Add("設計");
tasks.Add("実装");
tasks.Add("テスト");

固定長なら配列、可変長ならListと考えると選びやすくなります。

5. C#のクラス・オブジェクトを初期化する方法

5-1. newでインスタンスを作成する基本形

クラスを使うには、基本的にnewでインスタンスを作成します。

C#
User user = new User();

C# 9以降では、左辺の型から推論できる場合に次のように書けます。

C#
User user = new();

インスタンス化によって、クラスの実体がメモリ上に作成されます。

5-2. コンストラクターを使った初期化

コンストラクターは、クラスや構造体のインスタンスが作成されるときに呼び出される特別なメソッドです。Microsoftのドキュメントでも、コンストラクターはインスタンス作成時に呼び出され、オブジェクトを有効な状態にするために使えると説明されています。Microsoft Learn

C#
class User
{
public string Name { get; }

public User(string name)
{
Name = name;
}
}

使う側は次のように初期化します。

C#
var user = new User("Sato");

必須の値を確実に渡したい場合は、コンストラクターを使うと安全です。

5-3. デフォルトコンストラクターでの初期化

引数なしのコンストラクターをデフォルトコンストラクターと呼ぶことがあります。

C#
class User
{
public string Name { get; set; }

public User()
{
Name = "未設定";
}
}

この場合、new User()とした時点でNameに初期値が入ります。

C#
var user = new User();
Console.WriteLine(user.Name); // 未設定

5-4. 引数付きコンストラクターで初期値を渡す

初期化に必要な値を外部から渡したい場合は、引数付きコンストラクターを使います。

C#
class Product
{
public string Name { get; }
public int Price { get; }

public Product(string name, int price)
{
Name = name;
Price = price;
}
}
C#
var product = new Product("Keyboard", 5000);

この方法なら、NamePriceが未設定のままになることを防げます。

5-5. オブジェクト初期化子を使った書き方

オブジェクト初期化子を使うと、インスタンス作成と同時にプロパティへ値を設定できます。

C#
var user = new User
{
Id = 1,
Name = "Sato",
Age = 30
};

オブジェクト初期化子は、コンストラクターを明示的に呼び出した後に代入文を書く代わりに、作成時にアクセス可能なフィールドやプロパティへ値を設定する構文です。Microsoft Learn+1

5-6. コンストラクターとオブジェクト初期化子の違い

コンストラクターは、オブジェクトが成立するために必須の値を渡すのに向いています。

C#
var user = new User("Sato");

オブジェクト初期化子は、任意項目を読みやすく設定するのに向いています。

C#
var user = new User("Sato")
{
Age = 30,
Email = "sato@example.com"
};

必須項目はコンストラクター、任意項目はオブジェクト初期化子にすると、設計意図が分かりやすくなります。

5-7. ネストしたオブジェクトの初期化

オブジェクトの中に別のオブジェクトを持つ場合も、初期化子でまとめて書けます。

C#
var user = new User
{
Name = "Sato",
Address = new Address
{
PostalCode = "100-0001",
City = "Tokyo"
}
};

ネストが深くなりすぎる場合は、ファクトリメソッドやビルダーパターンを検討すると可読性が上がります。

5-8. クラス初期化で避けたい設計ミス

クラス初期化で避けたいのは、オブジェクトが不完全な状態で作れてしまう設計です。

C#
var order = new Order();
// order.CustomerIdが未設定
// order.Itemsがnull

このような状態を避けるには、コンストラクターで必須項目を受け取る、Listプロパティを空Listで初期化する、requiredを使うなどの方法があります。

C#
class Order
{
public int CustomerId { get; }
public List<OrderItem> Items { get; } = new();

public Order(int customerId)
{
CustomerId = customerId;
}
}

6. C#のプロパティを初期化する方法

6-1. 自動実装プロパティの初期化

自動実装プロパティは、宣言時に初期値を設定できます。

C#
class User
{
public string Name { get; set; } = "未設定";
public int Age { get; set; } = 0;
public bool IsActive { get; set; } = true;
}

この書き方は、単純な初期値を設定したいときに便利です。

6-2. コンストラクターでプロパティを初期化する

必須プロパティは、コンストラクターで初期化すると安全です。

C#
class User
{
public string Name { get; }

public User(string name)
{
Name = name;
}
}

getのみのプロパティでも、コンストラクター内では代入できます。

C#
var user = new User("Sato");

6-3. オブジェクト初期化子でプロパティに値を入れる

setアクセサがあるプロパティは、オブジェクト初期化子で値を設定できます。

C#
var user = new User
{
Name = "Sato",
Age = 30
};

オブジェクト初期化子は、DTOや設定クラスの初期化でよく使われます。

6-4. initアクセサを使った初期化専用プロパティ

initアクセサを使うと、オブジェクト初期化時だけ値を設定できるプロパティを作れます。

C#
class User
{
public string Name { get; init; } = "";
public int Age { get; init; }
}
C#
var user = new User
{
Name = "Sato",
Age = 30
};

// user.Name = "Suzuki"; // 初期化後は変更できない

initは、作成後に値を変更したくないオブジェクトに向いています。

6-5. requiredプロパティで初期化漏れを防ぐ

requiredを使うと、オブジェクト初期化時に必ず設定すべきプロパティを表現できます。

C#
class User
{
public required string Name { get; init; }
public int Age { get; init; }
}
C#
var user = new User
{
Name = "Sato",
Age = 30
};

requiredを付けたプロパティは、呼び出し側に初期化を求めることができます。Microsoftのドキュメントでも、requiredキーワードはオブジェクト初期化子でプロパティやフィールドの設定を強制するために使えると説明されています。Microsoft Learn

6-6. getのみ・private setプロパティの初期化

getのみのプロパティは、宣言時またはコンストラクターで初期化します。

C#
class Product
{
public string Name { get; }

public Product(string name)
{
Name = name;
}
}

private setは、クラスの外からは変更できませんが、クラス内からは変更できます。

C#
class User
{
public string Name { get; private set; } = "未設定";

public void ChangeName(string name)
{
Name = name;
}
}

外部から自由に変更させたくない場合は、getのみ、private setinitを使い分けます。

6-7. プロパティ初期化とnull許容参照型の注意点

null許容参照型を有効にしている場合、非nullableなプロパティは初期化漏れに注意が必要です。

C#
class User
{
public string Name { get; set; } = "";
}

初期値を入れないと、コンパイラ警告が出る場合があります。

C#
class User
{
public required string Name { get; init; }
}

""で初期化する、コンストラクターで受け取る、requiredを使うなど、プロパティの意味に合う方法を選びましょう。

7. C#の初期化子を理解する

7-1. オブジェクト初期化子とは

オブジェクト初期化子は、オブジェクト作成時にプロパティやフィールドへ値を設定する構文です。

C#
var user = new User
{
Name = "Sato",
Age = 30
};

複数の代入を1つのまとまりとして書けるため、初期状態が分かりやすくなります。

7-2. コレクション初期化子とは

コレクション初期化子は、ListやDictionaryなどのコレクションに初期要素を追加する構文です。

C#
var numbers = new List<int>
{
1,
2,
3
};

Addを何度も書くよりも簡潔です。

C#
var numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);

上のような処理を、初期化時にまとめて書けます。

7-3. 配列初期化子とは

配列初期化子は、配列の要素をまとめて指定する構文です。

C#
int[] numbers = { 1, 2, 3 };

型を明示して書くこともできます。

C#
int[] numbers = new int[] { 1, 2, 3 };

配列の要素数が初期値から決まるため、固定データの定義に向いています。

7-4. インデックス初期化子とは

Dictionaryなどでは、インデックス初期化子を使えます。

C#
var scores = new Dictionary<string, int>
{
["Sato"] = 90,
["Suzuki"] = 85,
["Tanaka"] = 92
};

キーと値の対応が見やすいため、設定値やマッピングの初期化で便利です。

7-5. 初期化子を使うメリット

初期化子を使うメリットは、コードが短くなり、初期状態が読みやすくなることです。

C#
var user = new User
{
Name = "Sato",
Age = 30,
IsActive = true
};

このように書くと、オブジェクトがどの状態で作られるのかが一目で分かります。

7-6. 初期化子を使うときの注意点

初期化子は便利ですが、複雑なロジックを書く場所ではありません。

C#
var user = new User
{
Name = GetName(),
Age = CalculateAge(),
IsActive = CheckStatus()
};

この程度なら問題ありませんが、処理が複雑になる場合は、ファクトリメソッドやコンストラクターに分けた方が読みやすくなります。

8. C#のデフォルト値とnullの扱い

8-1. 値型と参照型のデフォルト値

C#では、値型と参照型でデフォルト値の考え方が異なります。

値型の代表例は、intdoubleboolDateTimestructです。参照型の代表例は、string、配列、クラス、Listです。

C#
int number = default;       // 0
bool flag = default; // false
DateTime date = default; // 0001/01/01 00:00:00
string text = default; // null
User user = default; // null

参照型のデフォルト値は基本的にnullです。そのため、使う前にインスタンスを作る必要があります。

8-2. defaultキーワードを使った初期化

defaultキーワードを使うと、型に応じたデフォルト値で初期化できます。

C#
int count = default;
bool isDeleted = default;
string? message = default;

ジェネリック型で初期値を扱う場合にも使われます。

C#
T value = default!;

ただし、default!はnull警告を抑えるための書き方であり、実際に安全になるわけではありません。安易に使いすぎないようにしましょう。

8-3. nullで初期化してよいケース・避けるべきケース

nullで初期化してよいのは、「値が存在しない」ことを明確に表したい場合です。

C#
DateTime? completedAt = null;
string? middleName = null;

一方、常に使う予定のListや文字列をnullで初期化するのは避けた方が安全です。

C#
List<string> names = new();
string message = string.Empty;

使うたびにnullチェックが必要になる設計は、バグの原因になりやすいです。

8-4. NullReferenceExceptionを防ぐ初期化

NullReferenceExceptionは、nullの参照に対してメンバーへアクセスしたときに発生します。

C#
User? user = null;

// Console.WriteLine(user.Name); // 例外

防ぐには、使用前にnullチェックします。

C#
if (user is not null)
{
Console.WriteLine(user.Name);
}

また、Listやプロパティは空のオブジェクトで初期化しておくと安全です。

C#
class Team
{
public List<User> Members { get; } = new();
}

8-5. nullable・非nullableの初期化ルール

null許容参照型を有効にしている場合、stringはnullを想定しない型、string?はnullを許容する型として扱います。

C#
string name = "Sato";
string? nickname = null;

非nullableなプロパティには、コンストラクター、宣言時初期化、requiredなどで値を入れます。

C#
class User
{
public required string Name { get; init; }
}

nullを許容するかどうかを型で表現すると、初期化漏れを見つけやすくなります。

8-6. 初期化漏れを検出しやすくする書き方

初期化漏れを検出しやすくするには、次のような書き方が有効です。

C#
class User
{
public required string Name { get; init; }
public List<string> Roles { get; init; } = new();
}

必須項目はrequired、コレクションは空で初期化、nullを許容する値には?を付けると、コードの意図が明確になります。

9. 実務で使うC#初期化パターン

9-1. DTO・モデルクラスの初期化

DTOやモデルクラスでは、オブジェクト初期化子がよく使われます。

C#
var userDto = new UserDto
{
Id = 1,
Name = "Sato",
Email = "sato@example.com"
};

DTOはデータを運ぶためのクラスなので、プロパティをまとめて設定できる初期化子と相性が良いです。

9-2. 設定値・オプションオブジェクトの初期化

設定値をまとめるクラスでは、デフォルト値を持たせると使いやすくなります。

C#
class AppOptions
{
public int TimeoutSeconds { get; init; } = 30;
public bool EnableLogging { get; init; } = true;
public string ApiBaseUrl { get; init; } = "";
}

使う側では、必要な項目だけ上書きします。

C#
var options = new AppOptions
{
TimeoutSeconds = 60
};

9-3. Dictionaryの初期化

Dictionaryは、キーと値の対応を定義するときによく使います。

C#
var statusNames = new Dictionary<int, string>
{
[1] = "下書き",
[2] = "公開",
[3] = "停止"
};

古い書き方では次のようにも書けます。

C#
var statusNames = new Dictionary<int, string>
{
{ 1, "下書き" },
{ 2, "公開" },
{ 3, "停止" }
};

キーが重複すると例外になるため、初期化時には重複に注意しましょう。

9-4. record型の初期化

recordは、値のまとまりを表すのに便利です。

C#
public record UserDto(int Id, string Name);

初期化は次のように書けます。

C#
var user = new UserDto(1, "Sato");

プロパティ形式で書くこともできます。

C#
public record Product
{
public required int Id { get; init; }
public required string Name { get; init; }
}
C#
var product = new Product
{
Id = 1,
Name = "Keyboard"
};

9-5. テストコードでよく使う初期化

テストコードでは、テスト対象のデータを分かりやすく初期化することが重要です。

C#
var user = new User
{
Id = 1,
Name = "Test User",
Email = "test@example.com"
};

複数のテストで同じ初期化を使う場合は、ヘルパーメソッドに分けると保守しやすくなります。

C#
private static User CreateUser()
{
return new User
{
Id = 1,
Name = "Test User",
Email = "test@example.com"
};
}

9-6. LINQと組み合わせた初期化

LINQを使うと、既存データを変換してListを初期化できます。

C#
var names = users
.Select(user => user.Name)
.ToList();

匿名型のListを作ることもあります。

C#
var summaries = orders
.Select(order => new
{
order.Id,
Total = order.Items.Sum(item => item.Price)
})
.ToList();

初期化と変換を組み合わせることで、簡潔にデータを作れます。

9-7. Unity・ASP.NETなどで見かける初期化の違い

Unityでは、MonoBehaviournewで直接作成せず、StartAwakeで初期化する場面があります。

C#
void Start()
{
score = 0;
}

ASP.NETでは、DIコンテナによってクラスが生成され、コンストラクターで依存関係を受け取る初期化がよく使われます。

C#
public class UserService
{
private readonly IUserRepository _repository;

public UserService(IUserRepository repository)
{
_repository = repository;
}
}

同じC#でも、フレームワークによって初期化のタイミングや書き方が変わる点に注意しましょう。

10. C#初期化の注意点とよくあるエラー

10-1. 未割り当てのローカル変数エラー

ローカル変数は、読み取る前に必ず初期化されている必要があります。

C#
int count;
// Console.WriteLine(count); // エラー

対処法は、宣言時に初期化することです。

C#
int count = 0;
Console.WriteLine(count);

条件分岐がある場合は、すべての経路で代入されるようにします。

10-2. null参照による実行時エラー

参照型をnullのまま使うと、実行時エラーになります。

C#
List<string>? names = null;
// names.Add("Sato"); // NullReferenceException

最初から空のListで初期化しておくと安全です。

C#
List<string> names = new();
names.Add("Sato");

10-3. 配列・Listの初期化忘れ

配列やListは、変数を宣言しただけでは使えません。

C#
List<int> numbers;
// numbers.Add(1); // エラー

必ずインスタンスを作成します。

C#
List<int> numbers = new();
numbers.Add(1);

10-4. プロパティの初期化漏れ

非nullableなプロパティを初期化しないと、警告やバグの原因になります。

C#
class User
{
public string Name { get; set; } = "";
}

必須ならrequiredを使う方法もあります。

C#
class User
{
public required string Name { get; init; }
}

10-5. コンストラクターの呼び出し順序

C#では、フィールド初期化子やコンストラクターの実行順序がコードの結果に影響することがあります。クラスのフィールド初期化順序は仕様上定義されており、初期化順序が意味を持つケースがあります。Microsoft Learn

C#
class Sample
{
private int x = 10;
private int y;

public Sample()
{
y = x + 5;
}
}

複雑な初期化をフィールド初期化子に詰め込みすぎると分かりにくくなるため、必要に応じてコンストラクターにまとめましょう。

10-6. staticメンバーの初期化タイミング

staticメンバーは、型に属するメンバーです。インスタンスごとではなく、型ごとに1つだけ存在します。

C#
class AppSettings
{
public static readonly string AppName = "SampleApp";
}

staticフィールドの初期化は、型が初めて使われるタイミングに関係します。初期化処理が重い場合や外部リソースに依存する場合は、タイミングに注意が必要です。

10-7. 可読性を下げる初期化の書き方

初期化子は便利ですが、詰め込みすぎると読みづらくなります。

C#
var user = new User { Name = GetName(), Age = CalculateAge(), Address = new Address { City = GetCity(), PostalCode = GetPostalCode() } };

複雑な場合は、改行して整えるか、メソッドに分けましょう。

C#
var user = new User
{
Name = GetName(),
Age = CalculateAge(),
Address = CreateAddress()
};

読みやすい初期化は、保守しやすいコードにつながります。

11. C#初期化の書き方早見表

11-1. 変数初期化の書き方一覧

目的書き方
intを初期化int count = 0;
doubleを初期化double price = 0.0;
boolを初期化bool isActive = false;
stringを空文字で初期化string name = "";
stringをnull許容で初期化string? name = null;
varで初期化var count = 10;
defaultで初期化int count = default;

11-2. 配列初期化の書き方一覧

目的書き方
要素数を指定int[] numbers = new int[3];
初期値を指定int[] numbers = new int[] { 1, 2, 3 };
newを省略int[] numbers = { 1, 2, 3 };
空配列int[] numbers = Array.Empty<int>();
多次元配列int[,] matrix = new int[2, 3];
ジャグ配列int[][] values = new int[3][];

11-3. List初期化の書き方一覧

目的書き方
空のListvar list = new List<int>();
new()で初期化List<int> list = new();
要素ありvar list = new List<int> { 1, 2, 3 };
配列から作成var list = new List<int>(array);
容量指定var list = new List<int>(100);
オブジェクトListvar users = new List<User> { new User { Name = "Sato" } };

11-4. クラス初期化の書き方一覧

目的書き方
デフォルトコンストラクターvar user = new User();
new()で作成User user = new();
引数付きコンストラクターvar user = new User("Sato");
オブジェクト初期化子var user = new User { Name = "Sato" };
コンストラクター+初期化子var user = new User("Sato") { Age = 30 };

11-5. プロパティ初期化の書き方一覧

目的書き方
宣言時初期化public string Name { get; set; } = "";
コンストラクター初期化Name = name;
initpublic string Name { get; init; } = "";
requiredpublic required string Name { get; init; }
getのみpublic string Name { get; }
private setpublic string Name { get; private set; } = "";

11-6. 目的別に選ぶおすすめの初期化方法

単純な変数は宣言時に初期化します。

C#
int count = 0;

要素数が固定なら配列を使います。

C#
int[] numbers = { 1, 2, 3 };

要素数が変わるならListを使います。

C#
var numbers = new List<int>();

必須値があるクラスはコンストラクターで初期化します。

C#
var user = new User("Sato");

任意のプロパティが多い場合はオブジェクト初期化子を使います。

C#
var user = new User
{
Name = "Sato",
Age = 30
};

作成後に変更させたくない値はinitrecordを検討します。

12. C#の初期化に関するよくある質問

12-1. C#では変数を必ず初期化する必要がある?

ローカル変数は、値を読み取る前に必ず初期化する必要があります。

C#
int x;
// Console.WriteLine(x); // エラー

フィールドや配列要素はデフォルト値で自動的に初期化されます。

C#
class Sample
{
private int count; // 0
}

ただし、自動初期化に頼りすぎると意図が分かりにくくなるため、重要な値は明示的に初期化するのがおすすめです。

12-2. 配列とListはどちらを使えばよい?

要素数が固定なら配列、増減するならListを使うのが基本です。

C#
string[] fixedNames = { "A", "B", "C" };

var dynamicNames = new List<string>();
dynamicNames.Add("A");
dynamicNames.Add("B");

実務では、要素の追加や削除がある場面が多いため、Listの方がよく使われます。

12-3. コンストラクターとオブジェクト初期化子はどちらがよい?

必須項目はコンストラクター、任意項目はオブジェクト初期化子が向いています。

C#
var user = new User("Sato")
{
Age = 30
};

必ず必要な値をオブジェクト初期化子だけに任せると、設定漏れが起きる可能性があります。その場合は、コンストラクターやrequiredを使うと安全です。

12-4. stringはnullと空文字のどちらで初期化すべき?

基本的には、文字列として扱う予定があるなら空文字で初期化する方が安全です。

C#
string message = string.Empty;

値が存在しない可能性を表したい場合は、string?としてnullを許容します。

C#
string? comment = null;

空文字は「入力が空」、nullは「値が存在しない」と考えると使い分けやすくなります。

12-5. requiredとinitはいつ使う?

initは、初期化時だけ値を設定できるプロパティを作りたいときに使います。

C#
public string Name { get; init; } = "";

requiredは、呼び出し側に初期化を強制したいときに使います。

C#
public required string Name { get; init; }

作成後に変更させたくないが、作成時には必ず値を入れてほしい場合は、requiredinitの組み合わせが便利です。

12-6. 初期化と代入は何が違う?

初期化は、変数やオブジェクトに最初の値を設定することです。代入は、すでに存在する変数やプロパティに値を入れることです。

C#
int count = 0; // 初期化
count = 10; // 代入

初期化は「使い始めるための準備」、代入は「値の更新」と考えると分かりやすいです。

まとめ

C#の初期化は、変数、配列、List、クラス、プロパティを安全に扱うための重要な基礎です。

変数は、使う前に意味のある値で初期化します。配列は固定長のデータに向いており、要素数や初期値を指定して作成します。Listは要素の増減に向いており、空Listやコレクション初期化子を使って柔軟に初期化できます。

クラスやオブジェクトでは、new、コンストラクター、オブジェクト初期化子を使い分けることが大切です。必須の値はコンストラクターやrequiredで初期化し、任意の値はオブジェクト初期化子で設定すると、分かりやすく安全なコードになります。

プロパティでは、宣言時初期化、コンストラクター初期化、initrequiredprivate setなどを使い分けます。null許容参照型を有効にしている場合は、stringstring?の違いを意識し、初期化漏れをコンパイラに検出してもらう設計が有効です。

C#の初期化で迷ったときは、次の基準で考えると整理しやすくなります。

目的おすすめの初期化
単純な値を使う宣言時に初期化
要素数が固定配列
要素数が変わるList
必須値があるクラスコンストラクター
任意項目が多いオブジェクトオブジェクト初期化子
作成後に変更させたくないinit
初期化漏れを防ぎたいrequired
null参照を避けたい空文字・空List・nullチェック

初期化を正しく書けるようになると、C#コードの可読性、保守性、安全性が大きく向上します。