C# 文法一覧|初心者向けに基本構文からLINQまでサンプルコードで解説
はじめに
C#は、Windowsアプリ、Webアプリ、スマートフォンアプリ、ゲーム開発、クラウドサービスなど、幅広い分野で使われているプログラミング言語です。文法は比較的読みやすく、初心者でも基本構文を順番に学べば、実用的なプログラムを作れるようになります。
この記事では、C#の文法一覧として、変数、条件分岐、繰り返し、配列、メソッド、クラス、例外処理、LINQ、非同期処理、ファイル操作までをサンプルコード付きで解説します。C#をこれから学ぶ人はもちろん、学習中に文法を確認したい人にも使いやすい内容です。
1. C#文法一覧を学ぶ前に押さえる基礎知識
1-1. C#とは?特徴とできること
C#は、Microsoftが開発したオブジェクト指向プログラミング言語です。.NETという開発基盤の上で動作し、さまざまなアプリケーションを作成できます。
C#でできることの例は次のとおりです。
Webアプリ開発
デスクトップアプリ開発
ゲーム開発
スマートフォンアプリ開発
API開発
業務システム開発
クラウドアプリ開発
C#は型が明確で、文法も整理されているため、大規模な開発にも向いています。また、Visual StudioやVisual Studio Codeなどの開発環境が充実しており、初心者でも始めやすい言語です。
1-2. C#の文法を一覧で学ぶメリット
C#の文法を一覧で学ぶメリットは、全体像をつかみやすいことです。
プログラミング初心者は、変数、if文、for文、クラス、LINQなどを個別に学ぶことが多いですが、それぞれの文法がどのようにつながっているのかを理解しないと、実際のプログラムで使いこなすのが難しくなります。
文法一覧として学ぶことで、次のようなメリットがあります。
C#でよく使う構文をまとめて確認できる
忘れた文法をすぐに見直せる
学習の順番がわかりやすくなる
サンプルコードを比較しながら理解できる
実務で使う文法の基礎を固められる
特に初心者は、最初からすべてを完璧に覚える必要はありません。まずは「どのような文法があるのか」を把握し、必要に応じて使いながら覚えていくのがおすすめです。
1-3. C#の基本的なプログラム構造
C#の基本的なプログラムは、次のような構造で書きます。
C#using System;
class Program
{
static void Main()
{
Console.WriteLine("Hello, C#");
}
}
このコードでは、Mainメソッドがプログラムの開始地点になります。
それぞれの意味は次のとおりです。
C#using System;
System名前空間を使うための記述です。Console.WriteLineなどの基本機能を使うときに必要です。
C#class Program
{
}
C#では、基本的に処理をクラスの中に書きます。ここではProgramというクラスを定義しています。
C#static void Main()
{
}
プログラムの実行開始地点です。C#のコンソールアプリでは、Mainメソッドから処理が始まります。
C#Console.WriteLine("Hello, C#");
画面に文字列を表示する命令です。
最近のC#では、トップレベルステートメントを使って次のように短く書くこともできます。
C#Console.WriteLine("Hello, C#");
初心者は、まずシンプルな書き方で動かしながら、徐々にクラスやメソッドの構造を理解していくとよいでしょう。
1-4. サンプルコードの読み方と実行環境
この記事のサンプルコードは、主にコンソールアプリで実行することを想定しています。
C#を実行する環境としては、次のようなものがあります。
Visual Studio
Visual Studio Code
.NET SDK
オンラインC#実行環境
ローカル環境で実行する場合は、.NET SDKをインストールし、次のコマンドでコンソールアプリを作成できます。
Bashdotnet new console -n SampleApp
cd SampleApp
dotnet run
C#の学習では、コードを読むだけでなく、実際に書いて実行することが大切です。エラーが出た場合も、エラーメッセージを確認しながら修正することで理解が深まります。
2. C#の基本構文一覧
2-1. コメントの書き方
コメントは、プログラムの説明を書くための文法です。コメントとして書かれた部分は実行されません。
1行コメントは、//を使います。
C#// これは1行コメントです
Console.WriteLine("Hello");
複数行コメントは、/* */を使います。
C#/*
これは複数行コメントです。
複数行にわたって説明を書けます。
*/
Console.WriteLine("C#");
XMLドキュメントコメントは、メソッドやクラスの説明を書くときに使います。
C#/// <summary>
/// あいさつを表示します。
/// </summary>
void SayHello()
{
Console.WriteLine("Hello");
}
コメントは便利ですが、書きすぎると読みにくくなります。コードの意図や注意点を補足する目的で使うのが基本です。
2-2. 変数と定数の宣言
変数は、値を入れておくための箱のようなものです。
C#int age = 20;
string name = "Taro";
Console.WriteLine(age);
Console.WriteLine(name);
C#では、変数を宣言するときに型を指定します。
C#int number = 10;
double price = 1200.5;
bool isActive = true;
string message = "こんにちは";
値をあとから変更できない定数は、constを使います。
C#const double TaxRate = 0.1;
Console.WriteLine(TaxRate);
constで宣言した値は、プログラムの途中で変更できません。
C#const int MaxCount = 100;
// MaxCount = 200; // エラー
変更しない値には定数を使うと、コードの意味がわかりやすくなります。
2-3. データ型の種類
C#にはさまざまなデータ型があります。代表的な型は次のとおりです。
C#int count = 10; // 整数
long bigNumber = 100000L; // 大きな整数
float height = 170.5f; // 小数
double weight = 65.5; // 小数
decimal price = 1000.50m; // 金額などに使う小数
char grade = 'A'; // 1文字
string name = "Sato"; // 文字列
bool isValid = true; // 真偽値
よく使う型は、int、double、decimal、string、boolです。
金額計算では、誤差を避けるためにdecimalを使うことが多いです。
C#decimal price = 980m;
decimal tax = price * 0.1m;
Console.WriteLine(tax);
文字列はstring、真偽値はboolを使います。
C#string userName = "Alice";
bool isLogin = true;
型を正しく使うことで、エラーを防ぎやすくなります。
2-4. 型変換とキャスト
型変換とは、ある型の値を別の型に変えることです。
小さい範囲の型から大きい範囲の型へは、自動変換できます。
C#int number = 10;
double value = number;
Console.WriteLine(value);
一方、大きい範囲の型から小さい範囲の型へ変換する場合は、明示的なキャストが必要です。
C#double value = 10.5;
int number = (int)value;
Console.WriteLine(number); // 10
小数を整数にキャストすると、小数点以下は切り捨てられます。
文字列を数値に変換する場合は、int.ParseやTryParseを使います。
C#string text = "123";
int number = int.Parse(text);
Console.WriteLine(number);
変換に失敗する可能性がある場合は、TryParseが安全です。
C#string text = "abc";
if (int.TryParse(text, out int result))
{
Console.WriteLine(result);
}
else
{
Console.WriteLine("数値に変換できません");
}
実務では、ユーザー入力や外部データを扱う場面が多いため、TryParseを使う機会がよくあります。
2-5. 文字列の扱い方
C#では、文字列はstring型で扱います。
C#string firstName = "Taro";
string lastName = "Yamada";
string fullName = firstName + " " + lastName;
Console.WriteLine(fullName);
文字列を連結するには、+を使えます。
C#string message = "こんにちは、" + fullName + "さん";
Console.WriteLine(message);
現在は、文字列補間を使う書き方がよく使われます。
C#string name = "Taro";
int age = 20;
Console.WriteLine($"名前は{name}、年齢は{age}歳です");
文字列の長さはLengthで取得できます。
C#string text = "Hello";
Console.WriteLine(text.Length);
一部の文字列を取り出すにはSubstringを使います。
C#string text = "Hello C#";
string part = text.Substring(0, 5);
Console.WriteLine(part); // Hello
文字列に特定の文字が含まれているか調べるにはContainsを使います。
C#string text = "C# programming";
Console.WriteLine(text.Contains("C#")); // True
文字列は非常によく使うため、基本操作を早めに覚えておくと便利です。
2-6. 演算子の種類と使い方
C#では、計算や比較に演算子を使います。
算術演算子の例です。
C#int a = 10;
int b = 3;
Console.WriteLine(a + b); // 足し算
Console.WriteLine(a - b); // 引き算
Console.WriteLine(a * b); // 掛け算
Console.WriteLine(a / b); // 割り算
Console.WriteLine(a % b); // 余り
比較演算子は、条件分岐でよく使います。
C#int age = 20;
Console.WriteLine(age == 20); // 等しい
Console.WriteLine(age != 20); // 等しくない
Console.WriteLine(age > 18); // より大きい
Console.WriteLine(age >= 20); // 以上
Console.WriteLine(age < 30); // より小さい
Console.WriteLine(age <= 20); // 以下
論理演算子は、複数の条件を組み合わせるときに使います。
C#int age = 25;
bool hasTicket = true;
if (age >= 18 && hasTicket)
{
Console.WriteLine("入場できます");
}
if (age < 18 || hasTicket)
{
Console.WriteLine("条件のどちらかを満たしています");
}
if (!hasTicket)
{
Console.WriteLine("チケットがありません");
}
&&は「かつ」、||は「または」、!は「否定」を意味します。
3. 条件分岐の文法一覧
3-1. if文の基本構文
if文は、条件によって処理を分ける文法です。
C#int age = 20;
if (age >= 18)
{
Console.WriteLine("成人です");
}
条件式がtrueの場合だけ、波かっこの中の処理が実行されます。
C#int score = 80;
if (score >= 70)
{
Console.WriteLine("合格です");
}
条件式には、比較演算子や論理演算子を使えます。
C#int age = 25;
bool hasLicense = true;
if (age >= 18 && hasLicense)
{
Console.WriteLine("運転できます");
}
3-2. else if・elseの使い方
else ifを使うと、複数の条件を順番に判定できます。
C#int score = 75;
if (score >= 90)
{
Console.WriteLine("評価A");
}
else if (score >= 70)
{
Console.WriteLine("評価B");
}
else if (score >= 50)
{
Console.WriteLine("評価C");
}
else
{
Console.WriteLine("不合格");
}
elseは、どの条件にも当てはまらなかった場合に実行されます。
条件は上から順に判定されるため、順番が重要です。
C#int score = 95;
if (score >= 60)
{
Console.WriteLine("合格");
}
else if (score >= 90)
{
Console.WriteLine("高得点");
}
この例では、score >= 60が先に成立するため、score >= 90の処理には進みません。より厳しい条件を先に書くのが基本です。
3-3. switch文の基本構文
switch文は、値に応じて処理を分ける文法です。
C#int day = 3;
switch (day)
{
case 1:
Console.WriteLine("月曜日");
break;
case 2:
Console.WriteLine("火曜日");
break;
case 3:
Console.WriteLine("水曜日");
break;
default:
Console.WriteLine("不明な曜日");
break;
}
caseには比較したい値を書きます。breakを書くことで、処理を抜けます。
文字列でも使えます。
C#string command = "start";
switch (command)
{
case "start":
Console.WriteLine("開始します");
break;
case "stop":
Console.WriteLine("停止します");
break;
default:
Console.WriteLine("不明なコマンドです");
break;
}
条件が単純な値の比較であれば、if文よりswitch文のほうが読みやすい場合があります。
3-4. switch式の使い方
switch式は、値に応じて結果を返す書き方です。従来のswitch文よりも簡潔に書けます。
C#int day = 1;
string dayName = day switch
{
1 => "月曜日",
2 => "火曜日",
3 => "水曜日",
_ => "不明"
};
Console.WriteLine(dayName);
_は、どの条件にも当てはまらない場合を表します。
成績判定にも使えます。
C#int score = 85;
string result = score switch
{
>= 90 => "A",
>= 70 => "B",
>= 50 => "C",
_ => "D"
};
Console.WriteLine(result);
switch式は、条件ごとに値を返したい場合に便利です。
3-5. 三項演算子の使い方
三項演算子は、簡単な条件分岐を1行で書ける文法です。
C#int age = 20;
string result = age >= 18 ? "成人" : "未成年";
Console.WriteLine(result);
基本構文は次のとおりです。
C#条件 ? trueの場合の値 : falseの場合の値
例えば、点数によって合否を判定する場合は次のように書けます。
C#int score = 80;
string message = score >= 60 ? "合格" : "不合格";
Console.WriteLine(message);
三項演算子は便利ですが、複雑な条件を詰め込みすぎると読みにくくなります。複雑な分岐はif文を使うのがおすすめです。
4. 繰り返し処理の文法一覧
4-1. for文の基本構文
for文は、指定した回数だけ処理を繰り返す文法です。
C#for (int i = 0; i < 5; i++)
{
Console.WriteLine(i);
}
for文は、次の3つの要素で構成されます。
C#for (初期化; 条件; 更新)
{
繰り返す処理
}
配列の要素を順番に処理する場合にも使えます。
C#string[] names = { "Taro", "Hanako", "Jiro" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine(names[i]);
}
インデックス番号を使いたい場合は、for文が便利です。
4-2. while文の基本構文
while文は、条件がtrueの間、処理を繰り返します。
C#int count = 0;
while (count < 5)
{
Console.WriteLine(count);
count++;
}
条件が最初からfalseの場合、処理は一度も実行されません。
C#int count = 10;
while (count < 5)
{
Console.WriteLine(count);
}
while文では、条件がいつかfalseになるように注意する必要があります。更新処理を忘れると、無限ループになることがあります。
C#int count = 0;
while (count < 5)
{
Console.WriteLine(count);
count++; // 忘れないようにする
}
4-3. do while文の使い方
do while文は、最低1回は処理を実行してから条件を判定します。
C#int count = 0;
do
{
Console.WriteLine(count);
count++;
}
while (count < 5);
while文との違いは、条件判定のタイミングです。
C#int count = 10;
do
{
Console.WriteLine(count);
}
while (count < 5);
この例では、条件はfalseですが、処理は1回実行されます。
ユーザー入力を最低1回受け付けたい場合などに使われます。
C#string input;
do
{
Console.WriteLine("exitと入力すると終了します");
input = Console.ReadLine();
}
while (input != "exit");
4-4. foreach文の使い方
foreach文は、配列やコレクションの要素を順番に取り出す文法です。
C#string[] names = { "Taro", "Hanako", "Jiro" };
foreach (string name in names)
{
Console.WriteLine(name);
}
Listにも使えます。
C#List<int> numbers = new List<int> { 10, 20, 30 };
foreach (int number in numbers)
{
Console.WriteLine(number);
}
foreachは、インデックス番号が不要な場合に読みやすい書き方です。
C#foreach (var item in numbers)
{
Console.WriteLine(item);
}
要素を順番に処理するだけなら、for文よりforeach文のほうが簡潔です。
4-5. break・continueの使い方
breakは、ループを途中で終了します。
C#for (int i = 0; i < 10; i++)
{
if (i == 5)
{
break;
}
Console.WriteLine(i);
}
この例では、iが5になった時点でループを終了します。
continueは、現在の繰り返しをスキップして次の繰り返しに進みます。
C#for (int i = 0; i < 10; i++)
{
if (i % 2 == 0)
{
continue;
}
Console.WriteLine(i);
}
この例では、偶数をスキップして奇数だけを表示します。
breakとcontinueは便利ですが、多用すると処理の流れがわかりにくくなることがあります。必要な場面で適切に使いましょう。
5. 配列・コレクションの文法一覧
5-1. 配列の宣言と初期化
配列は、同じ型の複数の値をまとめて扱うための文法です。
C#int[] numbers = new int[3];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
Console.WriteLine(numbers[0]);
配列は、宣言と同時に初期化できます。
C#int[] numbers = { 10, 20, 30 };
string[] names = { "Taro", "Hanako", "Jiro" };
配列の要素数はLengthで取得できます。
C#int[] numbers = { 10, 20, 30 };
Console.WriteLine(numbers.Length);
配列の要素をすべて表示する場合は、foreachが便利です。
C#foreach (int number in numbers)
{
Console.WriteLine(number);
}
配列は要素数が固定です。あとから要素を追加したい場合は、Listを使うことが多いです。
5-2. 多次元配列とジャグ配列
多次元配列は、表のようなデータを扱うときに使います。
C#int[,] matrix = new int[2, 3];
matrix[0, 0] = 1;
matrix[0, 1] = 2;
matrix[0, 2] = 3;
matrix[1, 0] = 4;
matrix[1, 1] = 5;
matrix[1, 2] = 6;
Console.WriteLine(matrix[1, 2]); // 6
初期化と同時に値を入れることもできます。
C#int[,] matrix =
{
{ 1, 2, 3 },
{ 4, 5, 6 }
};
ジャグ配列は、配列の中に配列を持つ構造です。
C#int[][] jagged = new int[2][];
jagged[0] = new int[] { 1, 2 };
jagged[1] = new int[] { 3, 4, 5 };
Console.WriteLine(jagged[1][2]); // 5
多次元配列は行と列の数がそろった表に向いています。ジャグ配列は、行ごとに要素数が違うデータに向いています。
5-3. Listの使い方
List<T>は、要素を追加・削除できる可変長のコレクションです。
C#List<string> names = new List<string>();
names.Add("Taro");
names.Add("Hanako");
names.Add("Jiro");
Console.WriteLine(names[0]);
宣言と同時に初期化できます。
C#List<int> numbers = new List<int> { 10, 20, 30 };
要素を追加するにはAddを使います。
C#numbers.Add(40);
要素を削除するにはRemoveを使います。
C#numbers.Remove(20);
要素数はCountで取得します。
C#Console.WriteLine(numbers.Count);
要素を順番に処理するにはforeachを使います。
C#foreach (int number in numbers)
{
Console.WriteLine(number);
}
C#では、配列よりもListのほうが柔軟に扱えるため、実務でもよく使われます。
5-4. Dictionaryの使い方
Dictionary<TKey, TValue>は、キーと値の組み合わせでデータを管理するコレクションです。
C#Dictionary<string, int> scores = new Dictionary<string, int>();
scores["Taro"] = 80;
scores["Hanako"] = 95;
Console.WriteLine(scores["Taro"]);
初期化と同時に値を入れることもできます。
C#Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "Taro", 80 },
{ "Hanako", 95 },
{ "Jiro", 70 }
};
キーが存在するか確認するにはContainsKeyを使います。
C#if (scores.ContainsKey("Taro"))
{
Console.WriteLine(scores["Taro"]);
}
安全に値を取得したい場合は、TryGetValueが便利です。
C#if (scores.TryGetValue("Hanako", out int score))
{
Console.WriteLine(score);
}
else
{
Console.WriteLine("データがありません");
}
Dictionaryは、名前から点数を取得する、商品コードから商品情報を取得するなど、検索を素早く行いたい場面でよく使われます。
5-5. Queue・Stackの使い方
Queue<T>は、先に入れたデータを先に取り出すコレクションです。これをFIFOと呼びます。
C#Queue<string> queue = new Queue<string>();
queue.Enqueue("A");
queue.Enqueue("B");
queue.Enqueue("C");
Console.WriteLine(queue.Dequeue()); // A
Console.WriteLine(queue.Dequeue()); // B
次に取り出される要素を確認するにはPeekを使います。
C#Console.WriteLine(queue.Peek());
Stack<T>は、あとに入れたデータを先に取り出すコレクションです。これをLIFOと呼びます。
C#Stack<string> stack = new Stack<string>();
stack.Push("A");
stack.Push("B");
stack.Push("C");
Console.WriteLine(stack.Pop()); // C
Console.WriteLine(stack.Pop()); // B
Queueは順番待ち処理、Stackは戻る処理や履歴管理などで使われます。
5-6. コレクションを使い分けるポイント
C#には複数のコレクションがありますが、用途に応じて使い分けることが重要です。
要素数が固定でよい場合は、配列を使います。
C#int[] numbers = { 1, 2, 3 };
要素を追加・削除したい場合は、Listを使います。
C#List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);
キーで値を検索したい場合は、Dictionaryを使います。
C#Dictionary<string, string> users = new Dictionary<string, string>();
users["001"] = "Taro";
先に入れたものから処理したい場合はQueue、あとに入れたものから処理したい場合はStackを使います。
C#Queue<string> tasks = new Queue<string>();
Stack<string> history = new Stack<string>();
初心者は、まず配列、List、Dictionaryの3つを優先して覚えるとよいでしょう。
6. メソッド・関数の文法一覧
6-1. メソッドの定義と呼び出し
メソッドは、処理をひとまとまりにしたものです。
C#void SayHello()
{
Console.WriteLine("こんにちは");
}
SayHello();
メソッドを使うと、同じ処理を何度も書かずに済みます。
C#void PrintLine()
{
Console.WriteLine("----------------");
}
PrintLine();
Console.WriteLine("処理開始");
PrintLine();
メソッド名は、処理の内容がわかる名前にすると読みやすくなります。
C#void ShowUserName()
{
Console.WriteLine("Taro");
}
C#では、メソッドはクラスの中に定義するのが基本です。ただし、トップレベルステートメントでは、サンプルのように簡潔に書けます。
6-2. 引数と戻り値
引数は、メソッドに渡す値です。
C#void SayHello(string name)
{
Console.WriteLine($"こんにちは、{name}さん");
}
SayHello("Taro");
複数の引数を渡すこともできます。
C#void ShowProfile(string name, int age)
{
Console.WriteLine($"{name}さんは{age}歳です");
}
ShowProfile("Hanako", 25);
戻り値は、メソッドから返される値です。
C#int Add(int a, int b)
{
return a + b;
}
int result = Add(10, 20);
Console.WriteLine(result);
戻り値がない場合はvoidを使います。戻り値がある場合は、intやstringなどの型を指定します。
C#string GetMessage()
{
return "Hello";
}
Console.WriteLine(GetMessage());
6-3. ref・out・inパラメーター
refは、引数として渡した変数の値をメソッド内で変更したい場合に使います。
C#void AddTen(ref int number)
{
number += 10;
}
int value = 5;
AddTen(ref value);
Console.WriteLine(value); // 15
outは、メソッド内で値を設定して呼び出し元に返す場合に使います。
C#void GetValues(out int a, out int b)
{
a = 10;
b = 20;
}
GetValues(out int x, out int y);
Console.WriteLine(x);
Console.WriteLine(y);
TryParseでもoutが使われています。
C#string text = "123";
if (int.TryParse(text, out int number))
{
Console.WriteLine(number);
}
inは、値を読み取り専用として渡す場合に使います。
C#void PrintValue(in int number)
{
Console.WriteLine(number);
}
初心者は、まず通常の引数と戻り値を理解し、そのあとにref、out、inを学ぶとよいでしょう。
6-4. オーバーロード
オーバーロードとは、同じ名前のメソッドを、引数の型や数を変えて複数定義することです。
C#int Add(int a, int b)
{
return a + b;
}
double Add(double a, double b)
{
return a + b;
}
Console.WriteLine(Add(1, 2));
Console.WriteLine(Add(1.5, 2.5));
引数の数を変えることもできます。
C#void ShowMessage()
{
Console.WriteLine("メッセージなし");
}
void ShowMessage(string message)
{
Console.WriteLine(message);
}
ShowMessage();
ShowMessage("こんにちは");
オーバーロードを使うと、似た処理を同じメソッド名で扱えるため、コードがわかりやすくなります。
ただし、違いがわかりにくいオーバーロードを増やしすぎると、呼び出し側が混乱することがあります。
6-5. ラムダ式の基本
ラムダ式は、短い処理を簡潔に書くための文法です。
C#Func<int, int> square = x => x * x;
Console.WriteLine(square(5)); // 25
x => x * xは、「xを受け取り、x * xを返す」という意味です。
複数の引数を使う場合は、次のように書きます。
C#Func<int, int, int> add = (a, b) => a + b;
Console.WriteLine(add(10, 20));
戻り値がない処理にはActionを使えます。
C#Action<string> greet = name => Console.WriteLine($"こんにちは、{name}さん");
greet("Taro");
ラムダ式は、LINQやイベント処理でよく使われます。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(x => x % 2 == 0);
最初は難しく感じるかもしれませんが、「短く書けるメソッドのようなもの」と考えると理解しやすくなります。
7. クラスとオブジェクト指向の文法一覧
7-1. クラスとインスタンス
クラスは、データと処理をまとめるための設計図です。
C#class Person
{
public string Name;
public int Age;
public void SayHello()
{
Console.WriteLine($"こんにちは、{Name}です");
}
}
クラスから作られた実体をインスタンスと呼びます。
C#Person person = new Person();
person.Name = "Taro";
person.Age = 20;
person.SayHello();
newを使ってインスタンスを作成します。
C#Person p1 = new Person();
Person p2 = new Person();
クラスを使うと、関連するデータと処理をひとまとめにできるため、プログラムを整理しやすくなります。
7-2. フィールドとプロパティ
フィールドは、クラス内に持つ変数です。
C#class Person
{
public string name;
}
ただし、C#では外部から直接フィールドを操作するより、プロパティを使うのが一般的です。
C#class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
使い方は次のとおりです。
C#Person person = new Person();
person.Name = "Hanako";
person.Age = 25;
Console.WriteLine(person.Name);
読み取り専用のプロパティも作れます。
C#class Product
{
public string Name { get; }
public int Price { get; }
public Product(string name, int price)
{
Name = name;
Price = price;
}
}
プロパティを使うことで、データの取得や設定を安全に管理できます。
7-3. コンストラクター
コンストラクターは、インスタンスを作成するときに呼び出される特別なメソッドです。
C#class Person
{
public string Name { get; set; }
public Person(string name)
{
Name = name;
}
}
インスタンス作成時に値を渡せます。
C#Person person = new Person("Taro");
Console.WriteLine(person.Name);
複数の引数を持つコンストラクターも定義できます。
C#class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
}
使い方は次のとおりです。
C#Person person = new Person("Hanako", 25);
コンストラクターを使うと、必要な値を持った状態でインスタンスを作成できます。
7-4. アクセス修飾子
アクセス修飾子は、クラスやメンバーにどこからアクセスできるかを指定する文法です。
代表的なアクセス修飾子は次のとおりです。
C#public class Sample
{
public int PublicValue;
private int PrivateValue;
protected int ProtectedValue;
}
publicはどこからでもアクセスできます。
C#class Person
{
public string Name { get; set; }
}
privateは同じクラス内からだけアクセスできます。
C#class Counter
{
private int count = 0;
public void Increment()
{
count++;
}
public int GetCount()
{
return count;
}
}
protectedは、同じクラスと派生クラスからアクセスできます。
C#class Animal
{
protected string Name;
}
基本的には、外部に公開する必要があるものだけpublicにし、内部で使うものはprivateにするのがおすすめです。
7-5. 継承
継承は、既存のクラスの機能を引き継いで新しいクラスを作る文法です。
C#class Animal
{
public void Eat()
{
Console.WriteLine("食べます");
}
}
class Dog : Animal
{
public void Bark()
{
Console.WriteLine("ワン");
}
}
DogクラスはAnimalクラスを継承しているため、Eatメソッドを使えます。
C#Dog dog = new Dog();
dog.Eat();
dog.Bark();
継承を使うと、共通処理を親クラスにまとめられます。
C#class Employee
{
public string Name { get; set; }
public void Work()
{
Console.WriteLine($"{Name}が働いています");
}
}
class Engineer : Employee
{
public void Develop()
{
Console.WriteLine("開発しています");
}
}
ただし、継承を使いすぎると構造が複雑になることがあります。共通化したい理由が明確な場合に使うとよいでしょう。
7-6. オーバーライド
オーバーライドは、親クラスで定義されたメソッドを子クラスで上書きする文法です。
親クラスではvirtualを付けます。
C#class Animal
{
public virtual void Speak()
{
Console.WriteLine("鳴きます");
}
}
子クラスではoverrideを付けます。
C#class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}
使い方は次のとおりです。
C#Animal animal = new Animal();
animal.Speak();
Dog dog = new Dog();
dog.Speak();
親クラス型の変数に子クラスのインスタンスを入れても、子クラスのメソッドが呼び出されます。
C#Animal animal = new Dog();
animal.Speak(); // ワン
オーバーライドは、オブジェクト指向の重要な考え方であるポリモーフィズムに関係しています。
7-7. 抽象クラス
抽象クラスは、そのままインスタンス化できないクラスです。共通の設計を定義したいときに使います。
C#abstract class Animal
{
public abstract void Speak();
public void Eat()
{
Console.WriteLine("食べます");
}
}
抽象メソッドは、子クラスで必ず実装する必要があります。
C#class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワン");
}
}
使い方は次のとおりです。
C#Animal dog = new Dog();
dog.Speak();
dog.Eat();
抽象クラスは、共通処理を持ちながら、一部の処理を子クラスに任せたい場合に使います。
7-8. インターフェイス
インターフェイスは、クラスが実装すべき機能の約束を定義する文法です。
C#interface IFlyable
{
void Fly();
}
クラスでインターフェイスを実装します。
C#class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("飛びます");
}
}
使い方は次のとおりです。
C#IFlyable bird = new Bird();
bird.Fly();
複数のクラスで同じインターフェイスを実装できます。
C#class Airplane : IFlyable
{
public void Fly()
{
Console.WriteLine("飛行機が飛びます");
}
}
インターフェイスを使うと、「どのクラスか」ではなく「何ができるか」に注目して設計できます。
7-9. staticの使い方
staticは、インスタンスを作らずに使えるメンバーを定義する文法です。
C#class MathHelper
{
public static int Add(int a, int b)
{
return a + b;
}
}
呼び出すときは、クラス名から直接アクセスします。
C#int result = MathHelper.Add(10, 20);
Console.WriteLine(result);
staticフィールドも定義できます。
C#class Counter
{
public static int Count = 0;
}
使い方は次のとおりです。
C#Counter.Count++;
Console.WriteLine(Counter.Count);
ユーティリティ的な処理や、アプリ全体で共有したい値に使われることがあります。ただし、staticを多用するとテストしにくくなる場合があるため、使いどころには注意しましょう。
8. 例外処理の文法一覧
8-1. try-catch-finallyの基本構文
例外処理は、プログラム実行中に発生するエラーに対応するための文法です。
C#try
{
int number = int.Parse("abc");
Console.WriteLine(number);
}
catch (FormatException)
{
Console.WriteLine("数値形式が正しくありません");
}
finally
{
Console.WriteLine("処理を終了します");
}
tryには、例外が発生する可能性のある処理を書きます。
catchには、例外が発生したときの処理を書きます。
finallyには、例外の有無に関係なく必ず実行したい処理を書きます。
複数の例外を分けて処理することもできます。
C#try
{
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]);
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("配列の範囲外です");
}
catch (Exception ex)
{
Console.WriteLine($"エラーが発生しました: {ex.Message}");
}
最後にExceptionを指定すると、想定外の例外も受け取れます。
8-2. throwによる例外の発生
throwを使うと、意図的に例外を発生させることができます。
C#void CheckAge(int age)
{
if (age < 0)
{
throw new ArgumentException("年齢は0以上である必要があります");
}
Console.WriteLine(age);
}
呼び出し側では、try-catchで受け取れます。
C#try
{
CheckAge(-1);
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message);
}
不正な値が渡されたときに処理を続けると危険な場合、throwで明確にエラーを知らせることができます。
C#void Withdraw(int amount)
{
if (amount <= 0)
{
throw new ArgumentException("金額は1以上で指定してください");
}
}
例外は、単なるエラー表示ではなく、「この処理は正常に続けられない」ということを呼び出し元に伝える仕組みです。
8-3. 独自例外クラスの作り方
独自の例外クラスを作ることもできます。
C#class UserNotFoundException : Exception
{
public UserNotFoundException(string message) : base(message)
{
}
}
使い方は次のとおりです。
C#void FindUser(string userName)
{
if (userName != "Taro")
{
throw new UserNotFoundException("ユーザーが見つかりません");
}
}
呼び出し側では、独自例外を指定してcatchできます。
C#try
{
FindUser("Hanako");
}
catch (UserNotFoundException ex)
{
Console.WriteLine(ex.Message);
}
独自例外を使うと、エラーの意味を明確にできます。ただし、標準の例外で十分表現できる場合は、無理に独自例外を作る必要はありません。
8-4. 例外処理を書くときの注意点
例外処理を書くときは、何でもcatchして握りつぶさないように注意しましょう。
C#try
{
int number = int.Parse("abc");
}
catch
{
}
このように何も処理しないcatchを書くと、エラーの原因がわからなくなります。
最低限、ログやメッセージを出すようにします。
C#try
{
int number = int.Parse("abc");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
また、通常の条件分岐で対応できるものは、例外ではなくif文で処理するほうが自然です。
C#if (int.TryParse("123", out int number))
{
Console.WriteLine(number);
}
else
{
Console.WriteLine("変換できません");
}
例外処理は、予期しないエラーや、通常の流れでは処理できない問題に対応するために使いましょう。
9. LINQの文法一覧
9-1. LINQとは?
LINQは、配列やコレクションなどのデータを簡潔に操作するための機能です。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(x => x % 2 == 0);
foreach (int number in evenNumbers)
{
Console.WriteLine(number);
}
LINQを使うと、条件抽出、変換、並び替え、集計などを読みやすく書けます。
LINQを使うには、通常次の名前空間を使います。
C#using System.Linq;
C#では、LINQは実務でも非常によく使われます。特にListや配列を処理する場面では、覚えておくとコードがかなり簡潔になります。
9-2. Whereで条件を指定する
Whereは、条件に一致する要素だけを抽出します。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
var evenNumbers = numbers.Where(x => x % 2 == 0);
foreach (int number in evenNumbers)
{
Console.WriteLine(number);
}
文字列のリストから、特定の条件に一致する要素を取り出すこともできます。
C#List<string> names = new List<string> { "Taro", "Hanako", "Jiro" };
var result = names.Where(name => name.Contains("a"));
foreach (string name in result)
{
Console.WriteLine(name);
}
Whereの中には、trueまたはfalseを返す条件を書きます。
C#var adults = users.Where(user => user.Age >= 20);
条件抽出では、Whereが最も基本的なLINQメソッドです。
9-3. Selectで値を変換する
Selectは、要素を別の形に変換します。
C#List<int> numbers = new List<int> { 1, 2, 3 };
var squares = numbers.Select(x => x * x);
foreach (int value in squares)
{
Console.WriteLine(value);
}
文字列のリストから文字数だけを取り出すこともできます。
C#List<string> names = new List<string> { "Taro", "Hanako", "Jiro" };
var lengths = names.Select(name => name.Length);
foreach (int length in lengths)
{
Console.WriteLine(length);
}
オブジェクトのリストから特定のプロパティだけを取り出す場合にも使います。
C#var userNames = users.Select(user => user.Name);
Whereで絞り込み、Selectで変換する組み合わせは非常によく使われます。
C#var result = numbers
.Where(x => x % 2 == 0)
.Select(x => x * 10);
9-4. OrderByで並び替える
OrderByは、要素を昇順に並び替えます。
C#List<int> numbers = new List<int> { 3, 1, 5, 2, 4 };
var sorted = numbers.OrderBy(x => x);
foreach (int number in sorted)
{
Console.WriteLine(number);
}
降順に並び替える場合は、OrderByDescendingを使います。
C#var sortedDesc = numbers.OrderByDescending(x => x);
文字列も並び替えできます。
C#List<string> names = new List<string> { "Taro", "Hanako", "Jiro" };
var sortedNames = names.OrderBy(name => name);
foreach (string name in sortedNames)
{
Console.WriteLine(name);
}
オブジェクトのプロパティで並び替えることもできます。
C#var sortedUsers = users.OrderBy(user => user.Age);
複数条件で並び替える場合は、ThenByを使います。
C#var result = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name);
9-5. GroupByでグループ化する
GroupByは、指定したキーごとに要素をグループ化します。
C#List<string> names = new List<string> { "Taro", "Tom", "Hanako", "Hiro" };
var groups = names.GroupBy(name => name[0]);
foreach (var group in groups)
{
Console.WriteLine($"キー: {group.Key}");
foreach (var name in group)
{
Console.WriteLine(name);
}
}
オブジェクトのリストを分類する場合にも便利です。
C#var groups = users.GroupBy(user => user.Department);
部署ごとに人数を数える例です。
C#var result = users
.GroupBy(user => user.Department)
.Select(group => new
{
Department = group.Key,
Count = group.Count()
});
GroupByは、集計処理やレポート作成でよく使われます。
9-6. First・FirstOrDefaultの使い方
Firstは、条件に一致する最初の要素を取得します。
C#List<int> numbers = new List<int> { 10, 20, 30 };
int first = numbers.First();
Console.WriteLine(first);
条件を指定することもできます。
C#int result = numbers.First(x => x >= 20);
Console.WriteLine(result);
ただし、該当する要素がない場合、Firstは例外を発生させます。
C#// int result = numbers.First(x => x > 100); // 例外
該当する要素がない可能性がある場合は、FirstOrDefaultを使います。
C#int result = numbers.FirstOrDefault(x => x > 100);
Console.WriteLine(result); // 0
参照型の場合、見つからないとnullが返ることがあります。
C#string name = names.FirstOrDefault(x => x == "Alice");
データが存在するかわからない場合は、FirstOrDefaultを使うと安全です。
9-7. Any・All・Countの使い方
Anyは、条件に一致する要素が1つでもあるかを判定します。
C#List<int> numbers = new List<int> { 1, 2, 3, 4 };
bool hasEven = numbers.Any(x => x % 2 == 0);
Console.WriteLine(hasEven);
Allは、すべての要素が条件を満たすかを判定します。
C#bool allPositive = numbers.All(x => x > 0);
Console.WriteLine(allPositive);
Countは、要素数を取得します。
C#int count = numbers.Count();
Console.WriteLine(count);
条件に一致する要素数を数えることもできます。
C#int evenCount = numbers.Count(x => x % 2 == 0);
Console.WriteLine(evenCount);
Anyは存在チェック、Allは全体チェック、Countは件数確認に使います。
9-8. クエリ構文とメソッド構文の違い
LINQには、クエリ構文とメソッド構文があります。
クエリ構文の例です。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var result =
from number in numbers
where number % 2 == 0
select number;
メソッド構文の例です。
C#var result = numbers.Where(number => number % 2 == 0);
どちらも同じ結果になります。
複雑なデータ問い合わせではクエリ構文が読みやすい場合があります。一方、C#の実務ではメソッド構文がよく使われます。
C#var result = numbers
.Where(x => x % 2 == 0)
.Select(x => x * 10)
.OrderBy(x => x);
初心者は、まずメソッド構文から覚えるのがおすすめです。Where、Select、OrderBy、Countなどを使えるようになると、コレクション処理がかなり書きやすくなります。
10. 非同期処理の文法一覧
10-1. async・awaitの基本
asyncとawaitは、時間のかかる処理を待つための文法です。
C#async Task MainAsync()
{
await Task.Delay(1000);
Console.WriteLine("1秒待ちました");
}
asyncを付けたメソッドの中で、awaitを使えます。
C#async Task SayHelloAsync()
{
await Task.Delay(1000);
Console.WriteLine("Hello");
}
呼び出し側でもawaitします。
C#await SayHelloAsync();
非同期処理は、ファイル読み込み、Web API通信、データベースアクセスなど、時間がかかる処理でよく使われます。
10-2. Taskの使い方
Taskは、非同期処理を表す型です。
戻り値がない非同期メソッドは、Taskを返します。
C#async Task PrintAsync()
{
await Task.Delay(1000);
Console.WriteLine("完了");
}
戻り値がある非同期メソッドは、Task<T>を返します。
C#async Task<int> GetNumberAsync()
{
await Task.Delay(1000);
return 100;
}
呼び出し側では、awaitすると結果を取得できます。
C#int number = await GetNumberAsync();
Console.WriteLine(number);
複数の非同期処理をまとめて待つ場合は、Task.WhenAllを使います。
C#Task task1 = Task.Delay(1000);
Task task2 = Task.Delay(2000);
await Task.WhenAll(task1, task2);
Console.WriteLine("すべて完了");
10-3. 非同期メソッドの書き方
非同期メソッドは、メソッド名の末尾にAsyncを付けるのが一般的です。
C#async Task<string> GetMessageAsync()
{
await Task.Delay(1000);
return "完了しました";
}
呼び出し側は次のように書きます。
C#string message = await GetMessageAsync();
Console.WriteLine(message);
ファイルを非同期で読み込む例です。
C#string text = await File.ReadAllTextAsync("sample.txt");
Console.WriteLine(text);
非同期で書き込む例です。
C#await File.WriteAllTextAsync("sample.txt", "Hello C#");
非同期メソッドは、処理が終わるまでアプリ全体を止めたくない場合に役立ちます。特にGUIアプリやWebアプリでは重要な文法です。
10-4. 非同期処理で注意すべきポイント
非同期処理では、awaitを忘れないように注意しましょう。
C#GetMessageAsync(); // awaitしていない
awaitしないと、処理の完了を待たずに次の処理へ進んでしまいます。
C#string message = await GetMessageAsync();
また、非同期メソッドで例外が発生する場合もあります。
C#try
{
string message = await GetMessageAsync();
Console.WriteLine(message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
async voidは、イベントハンドラー以外では基本的に避けます。
C#// 基本的には避ける
async void DoSomething()
{
await Task.Delay(1000);
}
通常はTaskを返すようにします。
C#async Task DoSomethingAsync()
{
await Task.Delay(1000);
}
非同期処理は便利ですが、処理の順番や例外処理を意識して書くことが大切です。
11. ファイル操作の文法一覧
11-1. ファイルの読み込み
C#では、Fileクラスを使ってファイルを読み込めます。
C#string text = File.ReadAllText("sample.txt");
Console.WriteLine(text);
複数行を配列として読み込む場合は、ReadAllLinesを使います。
C#string[] lines = File.ReadAllLines("sample.txt");
foreach (string line in lines)
{
Console.WriteLine(line);
}
非同期で読み込む場合は、ReadAllTextAsyncを使います。
C#string text = await File.ReadAllTextAsync("sample.txt");
Console.WriteLine(text);
ファイルが存在するか確認するには、File.Existsを使います。
C#if (File.Exists("sample.txt"))
{
string text = File.ReadAllText("sample.txt");
Console.WriteLine(text);
}
else
{
Console.WriteLine("ファイルが見つかりません");
}
ファイル操作では、存在確認や例外処理を忘れないようにしましょう。
11-2. ファイルへの書き込み
ファイルに文字列を書き込むには、WriteAllTextを使います。
C#File.WriteAllText("sample.txt", "Hello C#");
複数行を書き込む場合は、WriteAllLinesを使います。
C#string[] lines = { "1行目", "2行目", "3行目" };
File.WriteAllLines("sample.txt", lines);
既存ファイルに追記する場合は、AppendAllTextを使います。
C#File.AppendAllText("sample.txt", "追記するテキスト");
非同期で書き込む場合は、WriteAllTextAsyncを使います。
C#await File.WriteAllTextAsync("sample.txt", "非同期で書き込み");
ファイル書き込みでは、既存ファイルが上書きされることがあります。必要に応じて、事前に確認処理を入れましょう。
C#if (!File.Exists("sample.txt"))
{
File.WriteAllText("sample.txt", "新規作成");
}
11-3. using文によるリソース管理
using文は、使い終わったリソースを自動的に解放するための文法です。
C#using (StreamWriter writer = new StreamWriter("sample.txt"))
{
writer.WriteLine("Hello");
}
usingブロックを抜けると、StreamWriterが自動的に破棄されます。
現在のC#では、using宣言も使えます。
C#using StreamWriter writer = new StreamWriter("sample.txt");
writer.WriteLine("Hello");
ファイルやデータベース接続など、使い終わったら閉じる必要があるものにはusingを使います。
読み込みでも使えます。
C#using StreamReader reader = new StreamReader("sample.txt");
string text = reader.ReadToEnd();
Console.WriteLine(text);
リソース管理を忘れると、ファイルがロックされたままになるなどの問題が起こることがあります。
11-4. ディレクトリ操作の基本
ディレクトリを作成するには、Directory.CreateDirectoryを使います。
C#Directory.CreateDirectory("data");
ディレクトリが存在するか確認するには、Directory.Existsを使います。
C#if (Directory.Exists("data"))
{
Console.WriteLine("ディレクトリがあります");
}
ディレクトリ内のファイル一覧を取得するには、GetFilesを使います。
C#string[] files = Directory.GetFiles("data");
foreach (string file in files)
{
Console.WriteLine(file);
}
ディレクトリ一覧を取得するには、GetDirectoriesを使います。
C#string[] directories = Directory.GetDirectories(".");
foreach (string directory in directories)
{
Console.WriteLine(directory);
}
ディレクトリを削除するには、Deleteを使います。
C#Directory.Delete("data");
中にファイルがあるディレクトリを削除する場合は、再帰削除を指定できます。
C#Directory.Delete("data", true);
削除処理は元に戻せないため、実行前に対象パスを十分確認しましょう。
12. C#でよく使う便利な文法一覧
12-1. varの使い方
varは、右辺から型を推論して変数を宣言する文法です。
C#var number = 10;
var name = "Taro";
var isActive = true;
この場合、numberはint、nameはstring、isActiveはboolとして扱われます。
LINQではvarがよく使われます。
C#var numbers = new List<int> { 1, 2, 3 };
var result = numbers.Where(x => x > 1);
ただし、varは型がなくなるわけではありません。コンパイル時には型が決まっています。
C#var count = 10;
// count = "文字列"; // エラー
型が明らかな場合はvarを使うと簡潔になりますが、型がわかりにくい場合は明示的に書いたほうが読みやすくなります。
12-2. nullable型とnull許容参照型
通常、intなどの値型にはnullを入れられません。
C#int number = 10;
// number = null; // エラー
nullを許可したい場合は、?を付けます。
C#int? number = null;
値があるかどうかはHasValueで確認できます。
C#int? number = 10;
if (number.HasValue)
{
Console.WriteLine(number.Value);
}
参照型でも、null許容参照型を使うと、nullの可能性を明示できます。
C#string? name = null;
nullでないことを前提に使う場合は、事前に確認します。
C#if (name != null)
{
Console.WriteLine(name.Length);
}
null許容の考え方は、null参照エラーを防ぐために重要です。
12-3. null合体演算子
null合体演算子??は、左辺がnullの場合に右辺の値を使う文法です。
C#string? name = null;
string displayName = name ?? "ゲスト";
Console.WriteLine(displayName);
nameがnullでなければnameの値、nullなら"ゲスト"が使われます。
設定値の初期値を決めるときにも便利です。
C#string? input = null;
string value = input ?? "未入力";
??=を使うと、nullの場合だけ代入できます。
C#string? name = null;
name ??= "ゲスト";
Console.WriteLine(name);
nullチェックを簡潔に書けるため、実務でもよく使われる文法です。
12-4. null条件演算子
null条件演算子?.は、対象がnullでない場合だけメンバーにアクセスします。
C#string? name = null;
int? length = name?.Length;
Console.WriteLine(length);
nameがnullの場合、例外は発生せず、結果はnullになります。
オブジェクトのプロパティにも使えます。
C#Person? person = null;
string? personName = person?.Name;
メソッド呼び出しにも使えます。
C#person?.SayHello();
?.と??を組み合わせることもよくあります。
C#string displayName = person?.Name ?? "名前なし";
null参照エラーを防ぎながら、コードを簡潔に書ける便利な文法です。
12-5. string interpolation
文字列補間は、文字列の中に変数や式を埋め込む文法です。
C#string name = "Taro";
int age = 20;
string message = $"名前は{name}、年齢は{age}歳です";
Console.WriteLine(message);
$を文字列の前に付け、{}の中に変数や式を書きます。
計算式も書けます。
C#int price = 1000;
int quantity = 3;
Console.WriteLine($"合計金額は{price * quantity}円です");
書式指定もできます。
C#decimal price = 1234.5m;
Console.WriteLine($"価格: {price:C}");
小数点以下の桁数を指定することもできます。
C#double rate = 0.12345;
Console.WriteLine($"{rate:P2}");
文字列連結より読みやすいため、現在のC#では文字列補間がよく使われます。
12-6. enumの使い方
enumは、決まった値の集合を名前付きで定義する文法です。
C#enum OrderStatus
{
Pending,
Shipped,
Delivered,
Canceled
}
使い方は次のとおりです。
C#OrderStatus status = OrderStatus.Shipped;
Console.WriteLine(status);
switch文と組み合わせると読みやすくなります。
C#switch (status)
{
case OrderStatus.Pending:
Console.WriteLine("処理待ち");
break;
case OrderStatus.Shipped:
Console.WriteLine("発送済み");
break;
case OrderStatus.Delivered:
Console.WriteLine("配達完了");
break;
case OrderStatus.Canceled:
Console.WriteLine("キャンセル");
break;
}
文字列や数値で状態を管理するよりも、enumを使うほうがミスを減らせます。
12-7. recordの使い方
recordは、データを表す型を簡潔に定義できる文法です。
C#record Person(string Name, int Age);
使い方は次のとおりです。
C#Person person = new Person("Taro", 20);
Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
recordは、値の比較がしやすいという特徴があります。
C#Person p1 = new Person("Taro", 20);
Person p2 = new Person("Taro", 20);
Console.WriteLine(p1 == p2); // True
一部の値だけを変更した新しいインスタンスを作るには、withを使います。
C#Person p1 = new Person("Taro", 20);
Person p2 = p1 with { Age = 21 };
Console.WriteLine(p2);
recordは、DTOや設定情報など、データ中心の型を作るときに便利です。
13. 初心者がつまずきやすいC#文法の注意点
13-1. ==とEqualsの違い
==は、値が等しいかを比較する演算子です。
C#int a = 10;
int b = 10;
Console.WriteLine(a == b); // True
文字列でも値の比較ができます。
C#string s1 = "Hello";
string s2 = "Hello";
Console.WriteLine(s1 == s2); // True
Equalsも等しいかを比較するメソッドです。
C#Console.WriteLine(s1.Equals(s2));
ただし、オブジェクトの場合は、比較の意味に注意が必要です。
C#Person p1 = new Person("Taro");
Person p2 = new Person("Taro");
Console.WriteLine(p1 == p2);
Console.WriteLine(p1.Equals(p2));
通常のクラスでは、同じ内容でも別インスタンスなら等しいとは限りません。一方、recordは値の内容で比較されます。
C#record User(string Name);
User u1 = new User("Taro");
User u2 = new User("Taro");
Console.WriteLine(u1 == u2); // True
比較したい対象が値なのか、同じインスタンスなのかを意識することが大切です。
13-2. 値型と参照型の違い
C#の型は、大きく値型と参照型に分けられます。
値型の例は次のとおりです。
C#int number = 10;
double price = 100.5;
bool isActive = true;
参照型の例は次のとおりです。
C#string name = "Taro";
Person person = new Person();
List<int> numbers = new List<int>();
値型は、変数に値そのものが入るイメージです。
C#int a = 10;
int b = a;
b = 20;
Console.WriteLine(a); // 10
Console.WriteLine(b); // 20
参照型は、オブジェクトへの参照を持ちます。
C#Person p1 = new Person();
p1.Name = "Taro";
Person p2 = p1;
p2.Name = "Hanako";
Console.WriteLine(p1.Name); // Hanako
p1とp2は同じインスタンスを参照しているため、一方を変更するともう一方にも影響します。
13-3. 配列とListの違い
配列は、要素数が固定です。
C#int[] numbers = new int[3];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
あとから要素数を簡単に増やすことはできません。
Listは、要素を追加・削除できます。
C#List<int> numbers = new List<int>();
numbers.Add(10);
numbers.Add(20);
numbers.Add(30);
numbers.Add(40);
要素数が最初から決まっている場合は配列、増減する可能性がある場合はListが向いています。
実務では、柔軟に扱えるListを使う場面が多いです。
C#List<string> names = new List<string> { "Taro", "Hanako" };
names.Add("Jiro");
names.Remove("Taro");
ただし、固定長のデータや高速なアクセスが必要な場面では、配列が適していることもあります。
13-4. public・privateの使い分け
publicは外部からアクセスできるメンバー、privateはクラス内部だけで使うメンバーです。
C#class Counter
{
private int count = 0;
public void Increment()
{
count++;
}
public int GetCount()
{
return count;
}
}
この例では、countを直接変更できないようにしています。
C#Counter counter = new Counter();
counter.Increment();
Console.WriteLine(counter.GetCount());
フィールドをすべてpublicにすると、どこからでも値を変更できてしまい、バグの原因になります。
C#class BadCounter
{
public int Count;
}
基本的には、内部の状態はprivateにし、必要な操作だけpublicメソッドやプロパティとして公開します。
C#class User
{
public string Name { get; private set; }
public User(string name)
{
Name = name;
}
}
外部に公開する範囲を小さくすることで、安全で保守しやすいコードになります。
13-5. null参照エラーを防ぐ方法
null参照エラーは、nullのオブジェクトにアクセスしようとしたときに発生します。
C#string? name = null;
// Console.WriteLine(name.Length); // エラーの原因
事前にnullチェックを行います。
C#if (name != null)
{
Console.WriteLine(name.Length);
}
null条件演算子を使う方法もあります。
C#int? length = name?.Length;
null合体演算子で初期値を設定することもできます。
C#string displayName = name ?? "ゲスト";
メソッドの引数でnullを受け取りたくない場合は、チェックして例外を投げることもあります。
C#void PrintName(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
Console.WriteLine(name);
}
C#では、null許容参照型を活用すると、nullの可能性をコード上で明確にできます。
C#string name = "Taro";
string? optionalName = null;
nullを許可するのか、許可しないのかを意識して設計することが大切です。
14. C#文法の学習順序
14-1. 初心者が最初に覚えるべき文法
C#初心者は、まず基本構文から学ぶのがおすすめです。
最初に覚えたい文法は次のとおりです。
変数
データ型
演算子
if文
switch文
for文
while文
配列
List
メソッド
最初からクラスやLINQを深く理解しようとすると、難しく感じることがあります。まずは、コンソールに文字を表示し、変数を使い、条件分岐と繰り返しを書けるようになることを目標にしましょう。
例えば、次のような簡単なプログラムを作れるようになると基礎が身につきます。
C#int score = 75;
if (score >= 60)
{
Console.WriteLine("合格");
}
else
{
Console.WriteLine("不合格");
}
その後、配列やListを使って複数のデータを処理できるようにします。
C#List<int> scores = new List<int> { 80, 70, 90 };
foreach (int score in scores)
{
Console.WriteLine(score);
}
14-2. アプリ開発前に理解したい文法
アプリ開発に進む前には、クラスとオブジェクト指向の基本を理解しておくとよいでしょう。
特に重要なのは次の文法です。
クラス
インスタンス
プロパティ
コンストラクター
アクセス修飾子
継承
インターフェイス
例外処理
ファイル操作
アプリ開発では、データと処理をクラスにまとめる場面が多くなります。
C#class Product
{
public string Name { get; set; }
public int Price { get; set; }
public Product(string name, int price)
{
Name = name;
Price = price;
}
}
また、ユーザー入力、ファイル、通信、データベースなどを扱うと、例外処理も重要になります。
C#try
{
string text = File.ReadAllText("sample.txt");
Console.WriteLine(text);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
基礎文法に加えて、クラス設計とエラー処理を理解しておくと、実践的な開発に進みやすくなります。
14-3. LINQ・非同期処理を学ぶタイミング
LINQは、配列やListの扱いに慣れてから学ぶのがおすすめです。
C#List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var result = numbers.Where(x => x % 2 == 0);
LINQを使うと、コレクション処理を簡潔に書けます。ただし、ラムダ式に慣れていないと最初は読みにくく感じるため、メソッドとラムダ式を学んだあとに取り組むと理解しやすくなります。
非同期処理は、ファイル操作、Web API、データベース処理などを学び始めるタイミングで理解するとよいでしょう。
C#async Task<string> LoadTextAsync()
{
return await File.ReadAllTextAsync("sample.txt");
}
最初から非同期処理を完璧に理解する必要はありません。まずは、asyncを付けたメソッドの中でawaitを使う、戻り値はTaskまたはTask<T>にする、という基本を押さえましょう。
14-4. 文法を効率よく身につける練習方法
C#の文法を効率よく身につけるには、小さなプログラムを繰り返し作ることが大切です。
例えば、次のような練習がおすすめです。
点数を入力して合否判定する
1から100までの合計を計算する
名前のリストを表示する
商品名と価格をクラスで管理する
ファイルにメモを書き込む
LINQで条件に合うデータを抽出する
文法を覚えるだけでなく、「どの場面で使うのか」を意識しましょう。
例えば、条件によって処理を変えたいならif文、同じ処理を繰り返したいならfor文やforeach文、複数のデータを扱いたいならList、データを分類・抽出したいならLINQを使います。
学習中は、エラーを恐れずにコードを書いて実行することが重要です。エラーが出たら、メッセージを読み、原因を調べて修正します。この繰り返しによって、C#の文法が自然に身についていきます。
まとめ
C#の文法一覧として、基本構文からLINQ、非同期処理、ファイル操作までを解説しました。
C#を学ぶうえで最初に押さえたいのは、変数、データ型、条件分岐、繰り返し、配列、List、メソッドです。これらを理解すると、簡単なコンソールアプリを作れるようになります。
次に、クラス、プロパティ、コンストラクター、アクセス修飾子、継承、インターフェイスなどのオブジェクト指向文法を学ぶと、より実践的なプログラムを書けるようになります。
さらに、LINQを使えばコレクション処理を簡潔に書けるようになり、非同期処理を理解すれば、ファイル操作やWeb通信などの時間がかかる処理にも対応できます。
C#の文法は数が多く見えますが、すべてを一度に覚える必要はありません。まずは基本構文を使って小さなプログラムを作り、必要に応じてクラス、例外処理、LINQ、非同期処理へと学習範囲を広げていきましょう。

