C#のnewとは?インスタンス生成・初期化・省略記法まで初心者向けにわかりやすく解説

はじめに

C#を学び始めると、かなり早い段階で登場するのがnewです。

C#
Person person = new Person();

このようなコードを見て、「newは何をしているのか」「なぜ必要なのか」「new()だけで書ける場合があるのはなぜか」と疑問に思う方は多いでしょう。

C#のnewは、主に型から新しいインスタンスを作るためのキーワードです。MicrosoftのC#リファレンスでも、new演算子は型の新しいインスタンスを作成するものとして説明されています。また、C#ではnewというキーワードが、インスタンス生成以外にも、継承時のメンバー隠蔽やジェネリック制約で使われることがあります。

この記事では、C#のnewについて、初心者でも理解しやすいように、インスタンス生成、初期化、省略記法、よくあるエラー、別の意味で使われるnewまで順番に解説します。

1. C#のnewとは?初心者がまず押さえる基本

1-1. newは「型から新しいインスタンスを作る」ためのキーワード

C#のnewは、クラスや構造体などの型をもとに、新しい実体を作るために使います。

たとえば、次のコードではPersonクラスから新しいインスタンスを作っています。

C#
Person person = new Person();

このコードは、ざっくり言うと次の意味です。

C#
Person型の変数personを用意し、Person型の新しいインスタンスを作って代入する

Personという設計図だけでは、まだ実際に使えるデータは存在しません。new Person()と書くことで、メモリ上に実体が作られ、その実体をperson変数から扱えるようになります。

1-2. クラス・インスタンス・オブジェクトの違い

newを理解するには、まず「クラス」「インスタンス」「オブジェクト」の違いを押さえておくとスムーズです。

クラスは設計図です。

C#
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

このPersonクラスは、「人を表すデータにはNameとAgeがある」という設計を表しています。ただし、この時点では具体的な人のデータはまだありません。

インスタンスは、その設計図から作られた実体です。

C#
Person person = new Person();

このnew Person()によって、Personクラスのインスタンスが作られます。

オブジェクトは、インスタンスとほぼ同じ意味で使われることが多い言葉です。厳密な文脈では違いを意識することもありますが、初心者のうちは「クラスからnewで作った実体」と考えれば十分です。

1-3. newを使うとメモリ上で何が起きるのか

newを使うと、C#の実行環境はその型のインスタンスを格納するための領域をメモリ上に確保します。

たとえば次のコードを考えます。

C#
Person person = new Person();

このとき、new Person()によってPersonオブジェクトがメモリ上に作られます。そして、変数personには、そのオブジェクトを参照するための情報が入ります。

参照型の変数には、オブジェクトそのものが丸ごと入るのではなく、オブジェクトへの参照が入ります。そのため、次のように別の変数へ代入しても、オブジェクト自体がコピーされるわけではありません。

C#
Person p1 = new Person();
Person p2 = p1;

この場合、p1p2は同じPersonインスタンスを参照します。

1-4. 「宣言」と「生成」と「初期化」の違い

C#のnewでつまずきやすいポイントに、「宣言」「生成」「初期化」の違いがあります。

宣言は、変数を用意することです。

C#
Person person;

この時点では、personという変数があるだけで、Personインスタンスはまだ作られていません。

生成は、newでインスタンスを作ることです。

C#
person = new Person();

これで、実際にPersonインスタンスが作られます。

初期化は、作ったインスタンスに初期値を設定することです。

C#
person.Name = "Taro";
person.Age = 20;

宣言、生成、初期化をまとめて書くと次のようになります。

C#
Person person = new Person();
person.Name = "Taro";
person.Age = 20;

さらに、オブジェクト初期化子を使えば、生成と初期化をまとめて書けます。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

2. C#でnewを使ったインスタンス生成の基本構文

2-1. 基本形:型名 変数名 = new 型名();

C#でnewを使う基本形は次のとおりです。

C#
型名 変数名 = new 型名();

たとえば、Personクラスのインスタンスを作るなら次のように書きます。

C#
Person person = new Person();

左側のPersonは変数の型です。右側のnew Person()は、新しいPersonインスタンスを作る処理です。

つまり、次のように読み取れます。

C#
Person型の変数personに、新しく作ったPersonインスタンスを代入する

2-2. 具体例:Personクラスをnewで生成する

まず、次のようなPersonクラスを用意します。

C#
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

このクラスをnewで生成します。

C#
Person person = new Person();

これで、person変数を通じてPersonインスタンスを操作できるようになります。

C#
person.Name = "Taro";
person.Age = 20;

Console.WriteLine(person.Name);
Console.WriteLine(person.Age);

実行すると、Taro20が表示されます。

2-3. newしたオブジェクトのプロパティやメソッドを使う方法

newで作ったオブジェクトは、変数名の後に.を付けてプロパティやメソッドを呼び出します。

C#
Person person = new Person();

person.Name = "Hanako";
person.Age = 25;

person.Introduce();

たとえば、Introduceメソッドを持つPersonクラスは次のように書けます。

C#
class Person
{
public string Name { get; set; }
public int Age { get; set; }

public void Introduce()
{
Console.WriteLine($"私は{Name}です。{Age}歳です。");
}
}

使い方は次のとおりです。

C#
Person person = new Person();
person.Name = "Hanako";
person.Age = 25;

person.Introduce();

newでインスタンスを作ったあと、そのインスタンスに対して値を設定したり、メソッドを実行したりできます。

2-4. nullのまま使う場合との違い

次のコードは注意が必要です。

C#
Person person = null;
person.Name = "Taro";

このコードでは、personnullです。つまり、どのインスタンスも参照していません。

その状態でperson.Nameにアクセスしようとすると、NullReferenceExceptionが発生します。

正しくは、先にnewでインスタンスを作ります。

C#
Person person = new Person();
person.Name = "Taro";

nullは「何も参照していない状態」です。参照型のオブジェクトを使う場合は、基本的にnewなどで実体が作られている必要があります。

3. newとコンストラクターの関係

3-1. コンストラクターとは何か

コンストラクターとは、インスタンスが作られるときに呼び出される特別なメソッドのようなものです。

C#
class Person
{
public Person()
{
Console.WriteLine("Personが作られました");
}
}

このクラスをnewすると、コンストラクターが実行されます。

C#
Person person = new Person();

実行結果は次のようになります。

C#
Personが作られました

new Person()Person()部分は、コンストラクター呼び出しと関係しています。

3-2. 引数なしコンストラクターでインスタンスを作る

引数なしコンストラクターは、引数を受け取らないコンストラクターです。

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

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

このクラスは次のようにnewできます。

C#
Person person = new Person();

Console.WriteLine(person.Name);

この場合、Nameには初期値として"未設定"が入ります。

引数なしコンストラクターは、初期値を固定したい場合や、あとからプロパティを設定したい場合に使いやすい書き方です。

3-3. 引数ありコンストラクターで初期値を渡す

コンストラクターには引数を持たせることもできます。

C#
class Person
{
public string Name { get; }
public int Age { get; }

public Person(string name, int age)
{
Name = name;
Age = age;
}
}

この場合、newするときに値を渡します。

C#
Person person = new Person("Taro", 20);

Console.WriteLine(person.Name);
Console.WriteLine(person.Age);

引数ありコンストラクターを使うと、インスタンス生成時に必要な値を確実に渡せます。

たとえば、「名前と年齢がないPersonは作らせたくない」という設計にしたい場合、引数ありコンストラクターは便利です。

3-4. コンストラクターのオーバーロードとnewの使い分け

C#では、引数の数や型が違えば、複数のコンストラクターを定義できます。これをコンストラクターのオーバーロードと呼びます。

C#
class Person
{
public string Name { get; }
public int Age { get; }

public Person()
{
Name = "未設定";
Age = 0;
}

public Person(string name)
{
Name = name;
Age = 0;
}

public Person(string name, int age)
{
Name = name;
Age = age;
}
}

使う側では、newの引数によって呼び出されるコンストラクターが変わります。

C#
Person p1 = new Person();
Person p2 = new Person("Taro");
Person p3 = new Person("Hanako", 25);

このように、同じPersonクラスでも、初期化に必要な情報に応じてnewの書き方を変えられます。

3-5. コンストラクターがないように見えるクラスでもnewできる理由

次のクラスには、コンストラクターが書かれていません。

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

しかし、次のようにnewできます。

C#
Person person = new Person();

これは、コンストラクターを明示的に定義していない場合、C#が引数なしコンストラクターを使えるようにしてくれるためです。

ただし、引数ありコンストラクターを自分で定義すると、引数なしコンストラクターが自動で使えるとは限りません。

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

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

この場合、次のコードはエラーになります。

C#
Person person = new Person();

正しくは、引数を渡して生成します。

C#
Person person = new Person("Taro");

4. C#のnewで使える初期化の書き方

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

オブジェクト初期化子とは、newでインスタンスを作ると同時に、プロパティやフィールドへ値を設定する書き方です。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

Microsoftの解説では、オブジェクト初期化子はコンストラクター呼び出し後に、アクセス可能なフィールドやプロパティへ値を割り当てる機能として説明されています。

通常の書き方と比べると、次のようにすっきり書けます。

C#
Person person = new Person();
person.Name = "Taro";
person.Age = 20;

オブジェクト初期化子を使うと、生成と初期化がまとまるため、コードの意図が読みやすくなります。

4-2. new Person { Name = "Taro", Age = 20 } の意味

次のコードを分解して考えてみます。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

これは、おおよそ次のコードと同じ意味です。

C#
Person person = new Person();
person.Name = "Taro";
person.Age = 20;

ただし、オブジェクト初期化子は「インスタンス生成時の初期値設定」としてまとまって見えるため、初期状態を表すのに向いています。

また、引数なしコンストラクターの()は省略できます。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

次のように書いても同じように使えます。

C#
Person person = new Person()
{
Name = "Taro",
Age = 20
};

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

コンストラクター初期化は、インスタンス生成時にコンストラクターへ値を渡す方法です。

C#
Person person = new Person("Taro", 20);

一方、オブジェクト初期化子は、インスタンスを作ったあとにプロパティへ値を設定する方法です。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

どちらを使うべきかは、設計によって変わります。

必ず必要な値は、コンストラクターで受け取ると安全です。

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

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

任意で設定する値や、設定項目が多い場合は、オブジェクト初期化子が読みやすいことがあります。

C#
Person person = new Person("Taro")
{
Age = 20,
Address = "Tokyo"
};

コンストラクターとオブジェクト初期化子は、どちらか一方しか使えないわけではありません。必要に応じて組み合わせられます。

4-4. コレクション初期化子でListやDictionaryを生成する

List<T>などのコレクションも、newと初期化子を組み合わせて作れます。

C#
List<string> names = new List<string>
{
"Taro",
"Hanako",
"Jiro"
};

これは、次のようにAddを呼び出す書き方に近い意味です。

C#
List<string> names = new List<string>();
names.Add("Taro");
names.Add("Hanako");
names.Add("Jiro");

Dictionary<TKey, TValue>も初期化できます。

C#
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "Taro", 80 },
{ "Hanako", 95 },
{ "Jiro", 70 }
};

より新しい書き方では、次のようにキーと値を指定することも多いです。

C#
Dictionary<string, int> scores = new Dictionary<string, int>
{
["Taro"] = 80,
["Hanako"] = 95,
["Jiro"] = 70
};

4-5. 配列をnewで生成・初期化する方法

配列もnewで作れます。

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

このコードでは、要素数3のint配列を作っています。各要素にはintの既定値である0が入ります。

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

値を指定して初期化する場合は、次のように書きます。

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

さらに、型が明らかな場合はnew int[]を省略できます。

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

文字列の配列も同じです。

C#
string[] names = new string[] { "Taro", "Hanako", "Jiro" };

または次のように書けます。

C#
string[] names = { "Taro", "Hanako", "Jiro" };

5. newを省略できる書き方・簡潔な記法

5-1. varとnewを組み合わせる書き方

C#では、varを使うと変数の型をコンパイラーに推論させられます。

C#
var person = new Person();

これは次のコードとほぼ同じ意味です。

C#
Person person = new Person();

varは型をなくす機能ではありません。右側のnew Person()から、左側の変数personの型がPersonだと判断されます。

たとえば次のコードでは、namesList<string>型になります。

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

varを使うとコードが短くなりますが、右側を見ても型が分かりにくい場合は、明示的に型名を書いたほうが読みやすいこともあります。

5-2. ターゲット型new:new()で型名を省略する

C#では、左側の型から右側の型が明らかな場合、new()のように型名を省略できます。これはターゲット型newと呼ばれる書き方です。

C#
Person person = new();

これは次のコードと同じ意味です。

C#
Person person = new Person();

List<string>でも使えます。

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

これは次のコードと同じです。

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

ただし、varとは組み合わせられません。

C#
var person = new(); // 型が分からないためエラー

new()は、左側や代入先から型が明確に分かる場合に使う省略記法です。

5-3. 配列初期化でnewを省略できるケース

配列では、変数の型が明らかな場合にnewを省略できます。

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

これは次のコードの省略形です。

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

ただし、次のようにあとから代入する場合は注意が必要です。

C#
int[] numbers;
numbers = { 1, 2, 3 }; // エラー

この場合は、newを使って書きます。

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

配列初期化でnewを省略できるのは、主に宣言と同時に初期化する場合です。

5-4. コレクション式による新しい初期化記法

C# 12以降では、コレクション式を使って、より簡潔にコレクションを初期化できます。コレクション式は、[]の中に要素を並べてコレクション値を作る構文です。

たとえば、配列は次のように書けます。

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

List<T>にも代入できます。

C#
List<string> names = ["Taro", "Hanako", "Jiro"];

従来の書き方は次のようなものでした。

C#
List<string> names = new List<string>
{
"Taro",
"Hanako",
"Jiro"
};

コレクション式を使うと、newを書かずにシンプルに初期化できます。

また、スプレッド要素を使って、別のコレクションを展開することもできます。

C#
int[] first = [1, 2, 3];
int[] second = [4, 5];

int[] all = [..first, ..second, 6];

allには1, 2, 3, 4, 5, 6が入ります。

5-5. 省略記法を使ってよい場面・避けたほうがよい場面

省略記法は便利ですが、常に使えばよいわけではありません。

使ってよい場面は、型が明らかで読みやすい場合です。

C#
Person person = new();
List<string> names = new();
int[] numbers = [1, 2, 3];

一方で、型が分かりにくくなる場合は避けたほうがよいです。

C#
var result = Create();

このようなコードは、Create()が何を返すのか分からないと、resultの型が読み取りにくくなります。

初心者のうちは、まず次の基本形をしっかり覚えるのがおすすめです。

C#
Person person = new Person();

そのうえで、コードを短くしたい場面や、チームのコーディング規約で許可されている場面でvarnew()を使うとよいでしょう。

6. newが必要な型・不要な型の違い

6-1. 参照型でnewがよく使われる理由

クラスは参照型です。参照型の変数は、オブジェクトへの参照を持ちます。

C#
Person person;

この宣言だけでは、Personインスタンスはまだ存在しません。

C#
person = new Person();

newすることで、実体が作られます。

参照型には、クラス、配列、string、インターフェイス型などがあります。ただし、インターフェイス型の変数には、インターフェイスを実装したクラスのインスタンスを代入します。

C#
IAnimal animal = new Dog();

この場合、IAnimal自体をnewしているのではなく、Dogクラスをnewしています。

6-2. 値型でもnewは使えるのか

intdoubleboolstructなどは値型です。値型でもnewは使えます。

C#
int number = new int();

この場合、numberにはintの既定値である0が入ります。

ただし、通常は次のように書くことが多いです。

C#
int number = 0;

構造体の場合は、newを使うことがあります。

C#
DateTime date = new DateTime(2026, 1, 1);

また、自作の構造体でもnewできます。

C#
struct Point
{
public int X { get; }
public int Y { get; }

public Point(int x, int y)
{
X = x;
Y = y;
}
}

Point point = new Point(10, 20);

値型はクラスとはメモリの扱いが異なりますが、コンストラクターを呼び出して初期化する目的でnewを使うことがあります。

6-3. stringでnewをあまり使わない理由

stringは参照型ですが、通常はnewを使わずに文字列リテラルで作ります。

C#
string name = "Taro";

次のようにnew string(...)と書ける場面もありますが、日常的な文字列作成ではほとんど使いません。

C#
char[] chars = { 'T', 'a', 'r', 'o' };
string name = new string(chars);

通常の文字列は、次のように書くのが自然です。

C#
string message = "Hello";

stringは参照型ですが、値のように扱いやすく設計されているため、初心者のうちは「文字列はnewせずにダブルクォーテーションで作る」と覚えて問題ありません。

6-4. staticクラスはnewできない

staticクラスはインスタンスを作れません。

C#
static class MathHelper
{
public static int Add(int a, int b)
{
return a + b;
}
}

このクラスは次のように使います。

C#
int result = MathHelper.Add(1, 2);

次のようにnewすることはできません。

C#
MathHelper helper = new MathHelper(); // エラー

staticクラスは、インスタンスごとの状態を持たず、クラス名から直接メソッドやプロパティを呼び出すためのものです。

6-5. interfaceやabstractクラスを直接newできない理由

インターフェイスは、実装を持つ具体的なクラスではありません。そのため、直接newできません。

C#
interface IAnimal
{
void Speak();
}

IAnimal animal = new IAnimal(); // エラー

正しくは、インターフェイスを実装したクラスをnewします。

C#
class Dog : IAnimal
{
public void Speak()
{
Console.WriteLine("Woof");
}
}

IAnimal animal = new Dog();

抽象クラスも同じように、直接newできません。

C#
abstract class Animal
{
public abstract void Speak();
}

Animal animal = new Animal(); // エラー

抽象クラスは、継承されることを前提とした未完成のクラスです。使うときは、具体的な派生クラスを作ってnewします。

C#
class Cat : Animal
{
public override void Speak()
{
Console.WriteLine("Meow");
}
}

Animal animal = new Cat();

7. C#のnewで初心者がつまずきやすいポイント

7-1. newし忘れによるNullReferenceException

初心者がよく遭遇するエラーが、NullReferenceExceptionです。

C#
Person person = null;
person.Name = "Taro";

personnullのままなので、Nameにアクセスできません。

正しくは、先にnewします。

C#
Person person = new Person();
person.Name = "Taro";

また、クラスの中に別のクラス型プロパティがある場合も注意が必要です。

C#
class Person
{
public Address Address { get; set; }
}

class Address
{
public string City { get; set; }
}

次のコードはエラーになります。

C#
Person person = new Person();
person.Address.City = "Tokyo"; // Addressがnullなのでエラー

Addressnewする必要があります。

C#
Person person = new Person();
person.Address = new Address();
person.Address.City = "Tokyo";

または、オブジェクト初期化子でまとめて書けます。

C#
Person person = new Person
{
Address = new Address
{
City = "Tokyo"
}
};

7-2. 配列をnewしただけでは中身のオブジェクトは作られない

配列をnewすると、配列そのものは作られます。

C#
Person[] people = new Person[3];

しかし、この時点で作られているのは「Personを3つ入れられる配列」です。中身のPersonインスタンスはまだ作られていません。

そのため、次のコードはエラーになります。

C#
people[0].Name = "Taro"; // people[0]がnull

各要素に対してnewが必要です。

C#
Person[] people = new Person[3];

people[0] = new Person();
people[0].Name = "Taro";

まとめて初期化することもできます。

C#
Person[] people =
{
new Person { Name = "Taro" },
new Person { Name = "Hanako" },
new Person { Name = "Jiro" }
};

「配列をnewすること」と「配列の中身のオブジェクトをnewすること」は別だと覚えておきましょう。

7-3. 同じクラスをnewすると別インスタンスになる

同じクラスを複数回newすると、それぞれ別のインスタンスが作られます。

C#
Person p1 = new Person();
Person p2 = new Person();

p1.Name = "Taro";
p2.Name = "Hanako";

Console.WriteLine(p1.Name); // Taro
Console.WriteLine(p2.Name); // Hanako

p1p2は同じPersonクラスから作られていますが、別々のオブジェクトです。

たとえるなら、同じ設計図から作った2台の車のようなものです。設計図は同じでも、それぞれ別の実体として存在します。

7-4. 代入してもオブジェクトがコピーされるわけではない

参照型では、変数を代入してもオブジェクトそのものがコピーされるわけではありません。

C#
Person p1 = new Person();
p1.Name = "Taro";

Person p2 = p1;
p2.Name = "Hanako";

Console.WriteLine(p1.Name); // Hanako

p2 = p1;によって、p2p1と同じインスタンスを参照します。そのため、p2.Nameを変更すると、p1.Nameを見たときにも変更が反映されています。

別のインスタンスを作りたい場合は、改めてnewします。

C#
Person p1 = new Person();
p1.Name = "Taro";

Person p2 = new Person();
p2.Name = p1.Name;

この場合、p1p2は別インスタンスです。

7-5. newしすぎるとコードが読みにくくなるケース

newは必要な場面で使うものですが、あちこちで直接newしすぎると、コードが読みにくくなることがあります。

C#
var order = new Order(
new Customer("Taro", new Address("Tokyo")),
new List<OrderItem>
{
new OrderItem(new Product("Book"), 2),
new OrderItem(new Product("Pen"), 5)
}
);

このようなコードは、何を作っているのか把握しにくくなります。

読みやすくするには、変数に分ける方法があります。

C#
var address = new Address("Tokyo");
var customer = new Customer("Taro", address);

var book = new Product("Book");
var pen = new Product("Pen");

var items = new List<OrderItem>
{
new OrderItem(book, 2),
new OrderItem(pen, 5)
};

var order = new Order(customer, items);

また、生成処理が複雑な場合は、ファクトリーメソッドやDIコンテナを使う設計もあります。

初心者のうちは、まずnewを正しく使えることが大切です。そのうえで、複雑な生成処理が増えてきたら、設計を見直すとよいでしょう。

8. C#のnewには別の意味もある

8-1. インスタンス生成のnew演算子

ここまで解説してきたnewは、インスタンス生成のためのnewです。

C#
Person person = new Person();

これは「Person型の新しいインスタンスを作る」という意味です。

C#で最もよく使うnewは、このインスタンス生成のnewです。初心者がまず覚えるべきなのも、この使い方です。

8-2. 継承時に使うnew修飾子

C#には、継承時に使うnew修飾子もあります。

C#
class BaseClass
{
public void Show()
{
Console.WriteLine("Base");
}
}

class DerivedClass : BaseClass
{
public new void Show()
{
Console.WriteLine("Derived");
}
}

このnewは、インスタンスを生成しているわけではありません。基底クラスのメンバーを、派生クラス側で明示的に隠すためのものです。

MicrosoftのC#リファレンスでは、new修飾子は基底クラスが提供するメンバーを明示的に隠すために使うものとして説明されています。

使い方は次のようになります。

C#
DerivedClass derived = new DerivedClass();
derived.Show(); // Derived

ただし、継承でメソッドの動作を差し替えたい場合は、newではなくvirtualoverrideを使うことが多いです。

C#
class BaseClass
{
public virtual void Show()
{
Console.WriteLine("Base");
}
}

class DerivedClass : BaseClass
{
public override void Show()
{
Console.WriteLine("Derived");
}
}

初心者のうちは、「継承時のnewはインスタンス生成とは別物」と覚えておきましょう。

8-3. ジェネリック制約のnew()

ジェネリックでは、new()という制約が使われることがあります。

C#
class Factory<T> where T : new()
{
public T Create()
{
return new T();
}
}

このwhere T : new()は、「Tには引数なしのpublicコンストラクターが必要」という意味です。Microsoftのドキュメントでも、new制約は型引数がpublicな引数なしコンストラクターを持つことを指定し、抽象型には使えないと説明されています。

たとえば、次のようなクラスは使えます。

C#
class Person
{
public Person()
{
}
}
C#
Factory<Person> factory = new Factory<Person>();
Person person = factory.Create();

一方、引数なしコンストラクターがないクラスでは使えません。

C#
class Person
{
public Person(string name)
{
}
}

この場合、where T : new()を満たせないため、Factory<Person>として使えません。

8-4. それぞれのnewを混同しないための見分け方

C#のnewには複数の意味がありますが、出てくる場所を見れば区別できます。

インスタンス生成のnewは、式の中に出てきます。

C#
Person person = new Person();

継承時のnew修飾子は、メソッドやプロパティなどの宣言に付きます。

C#
public new void Show()
{
}

ジェネリック制約のnew()は、where句の中に出てきます。

C#
where T : new()

同じnewというキーワードでも、使われる場所によって意味が変わります。

初心者はまず、インスタンス生成のnewをしっかり理解しましょう。そのあとで、継承やジェネリックを学ぶときに、別の意味のnewを整理していくと理解しやすくなります。

9. 実践で覚えるC#のnewの使い方

9-1. クラスを作ってnewするサンプル

まずは、シンプルなクラスを作ってnewしてみましょう。

C#
class Person
{
public string Name { get; set; }
public int Age { get; set; }

public void Introduce()
{
Console.WriteLine($"名前は{Name}、年齢は{Age}歳です。");
}
}

使う側のコードです。

C#
Person person = new Person();

person.Name = "Taro";
person.Age = 20;

person.Introduce();

実行結果は次のようになります。

C#
名前はTaro、年齢は20歳です。

この例では、new Person()でインスタンスを作り、そのあとでプロパティを設定しています。

9-2. コンストラクターで初期化するサンプル

次に、コンストラクターで初期化する形に変えてみます。

C#
class Person
{
public string Name { get; }
public int Age { get; }

public Person(string name, int age)
{
Name = name;
Age = age;
}

public void Introduce()
{
Console.WriteLine($"名前は{Name}、年齢は{Age}歳です。");
}
}

使う側のコードです。

C#
Person person = new Person("Taro", 20);

person.Introduce();

コンストラクターを使うと、newの時点で必要な値を渡せます。

この書き方は、インスタンスを作ったあとに値を入れ忘れるミスを減らせます。

9-3. オブジェクト初期化子で書き換えるサンプル

次は、オブジェクト初期化子を使った書き方です。

C#
class Person
{
public string Name { get; set; }
public int Age { get; set; }

public void Introduce()
{
Console.WriteLine($"名前は{Name}、年齢は{Age}歳です。");
}
}

使う側は次のようになります。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

person.Introduce();

生成と初期化がまとまっているため、どの値でインスタンスを作っているのか分かりやすい書き方です。

さらに、ターゲット型newを使うと次のようにも書けます。

C#
Person person = new()
{
Name = "Taro",
Age = 20
};

9-4. ListやDictionaryをnewで作るサンプル

List<T>newで作る例です。

C#
List<Person> people = new List<Person>
{
new Person { Name = "Taro", Age = 20 },
new Person { Name = "Hanako", Age = 25 },
new Person { Name = "Jiro", Age = 30 }
};

ループで表示してみます。

C#
foreach (Person person in people)
{
Console.WriteLine($"{person.Name}: {person.Age}");
}

Dictionary<TKey, TValue>を作る例です。

C#
Dictionary<string, int> scores = new Dictionary<string, int>
{
["Taro"] = 80,
["Hanako"] = 95,
["Jiro"] = 70
};

値を取り出すには、キーを指定します。

C#
Console.WriteLine(scores["Hanako"]); // 95

コレクションを使うときも、基本はnewでインスタンスを作ってから使います。

9-5. new()省略記法を使ったサンプル

ターゲット型newを使うと、型名の重複を減らせます。

C#
Person person = new();

コレクションでも使えます。

C#
List<string> names = new()
{
"Taro",
"Hanako",
"Jiro"
};

Dictionaryでは、特に型名が長くなりやすいため便利です。

C#
Dictionary<string, List<int>> scores = new()
{
["Taro"] = new List<int> { 80, 90, 85 },
["Hanako"] = new List<int> { 95, 88, 92 }
};

さらに内側にもnew()を使えます。

C#
Dictionary<string, List<int>> scores = new()
{
["Taro"] = new() { 80, 90, 85 },
["Hanako"] = new() { 95, 88, 92 }
};

ただし、省略しすぎると初心者には読みにくくなることがあります。学習中は、まず省略しない書き方を理解してから使うのがおすすめです。

10. C#のnewに関するよくある質問

10-1. C#では毎回newが必要ですか?

毎回必要なわけではありません。

クラスのインスタンスを新しく作る場合は、基本的にnewを使います。

C#
Person person = new Person();

一方、すでに作られたオブジェクトを受け取る場合は、newしません。

C#
void PrintName(Person person)
{
Console.WriteLine(person.Name);
}

また、intboolのような値型では、通常はリテラルを代入します。

C#
int age = 20;
bool isActive = true;

文字列も通常はnewを使いません。

C#
string name = "Taro";

つまり、newが必要かどうかは、「新しいインスタンスを作りたいかどうか」で判断します。

10-2. newとvarは何が違いますか?

newはインスタンスを作るためのキーワードです。

C#
new Person()

varは変数の型を推論させるためのキーワードです。

C#
var person = new Person();

このコードでは、new Person()によってPersonインスタンスを作り、varによって変数personの型がPersonだと推論されます。

つまり、newvarは役割がまったく違います。

C#
Person person = new Person();
var person2 = new Person();

どちらもPerson型の変数になりますが、左側の書き方が違うだけです。

10-3. new()とnew 型名()はどちらを使うべきですか?

初心者のうちは、まずnew 型名()を使う書き方から覚えるのがおすすめです。

C#
Person person = new Person();

この書き方は、何のインスタンスを作っているのかが明確です。

慣れてきたら、型が明らかな場面でnew()を使うとよいでしょう。

C#
Person person = new();

チーム開発では、プロジェクトのコーディング規約に合わせることも大切です。

読みやすさを優先するなら、型名を書いたほうが分かりやすい場面もあります。コードが長くなりすぎる場合や、左側の型で十分に分かる場合は、new()を使うとすっきりします。

10-4. newしたオブジェクトはいつ消えますか?

C#でnewしたオブジェクトは、使われなくなるとガベージコレクションの対象になります。

たとえば、次のようなコードを考えます。

C#
Person person = new Person();
person = null;

personが参照していたオブジェクトに、ほかのどこからも参照がなくなれば、そのオブジェクトは将来的にガベージコレクションによって回収されます。

ただし、いつ回収されるかを通常のコードから正確に指定することはできません。

C#では、多くの場合、メモリ解放を手動で行う必要はありません。ただし、ファイル、データベース接続、ネットワーク接続などの外部リソースを扱う場合は、Disposeusingを使って明示的に解放することがあります。

C#
using FileStream stream = new FileStream("sample.txt", FileMode.Open);

通常のオブジェクトはガベージコレクションに任せ、外部リソースは適切に解放する、という考え方が大切です。

10-5. 初心者はどの書き方から覚えるべきですか?

初心者は、まず次の基本形から覚えるのがおすすめです。

C#
Person person = new Person();

この形を理解すれば、C#のnewの基本である「型からインスタンスを作る」という考え方が身につきます。

次に、プロパティへの代入を覚えます。

C#
person.Name = "Taro";
person.Age = 20;

そのあとで、オブジェクト初期化子を覚えます。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

さらに慣れてきたら、varnew()の省略記法を使うとよいでしょう。

C#
var person = new Person();

Person anotherPerson = new();

最初から省略記法ばかり使うと、何が起きているのか分かりにくくなることがあります。まずは省略しない基本形を理解し、そのあとで短い書き方を学ぶ流れがおすすめです。

まとめ

C#のnewは、型から新しいインスタンスを作るための重要なキーワードです。

基本形は次のとおりです。

C#
Person person = new Person();

このコードでは、Person型の新しいインスタンスを作り、それをperson変数に代入しています。

newを理解するうえでは、次のポイントが大切です。

  • クラスは設計図、インスタンスはnewで作られる実体

  • 宣言だけではオブジェクトは作られない

  • 参照型をnullのまま使うとNullReferenceExceptionが起きる

  • コンストラクターはnewのタイミングで呼び出される

  • オブジェクト初期化子を使うと、生成と初期化をまとめて書ける

  • varnew()を使うとコードを短くできる

  • 配列をnewしても、中身の参照型オブジェクトは別途newが必要

  • C#のnewには、インスタンス生成以外に、継承時のnew修飾子やジェネリック制約のnew()もある

初心者はまず、次の書き方をしっかり身につけましょう。

C#
Person person = new Person();

そのうえで、コンストラクター、オブジェクト初期化子、var、ターゲット型new、コレクション式へと学習を広げていくと、C#のnewを実践的に使いこなせるようになります。