C#演習問題100選|初心者が基礎から実務レベルまで学べる解答・解説付き

C#演習問題100選|初心者が基礎から実務レベルまで学べる解答・解説付き

はじめに

C#の文法を読んだだけでは、プログラムを自力で書けるようにはなりません。変数、条件分岐、繰り返し処理、配列、クラスなどの知識を定着させるには、実際にコードを書き、エラーを修正しながら動作を確認することが重要です。

この記事では、C#初心者が基礎から実務に近い処理まで段階的に学べるよう、100問のC#演習問題を用意しました。各問題には解答例と解説があるため、独学の教材としても利用できます。

コード例は、基本的にコンソールアプリで実行できる形式です。必要に応じて、次の名前空間を追加してください。

using System;using System.Collections.Generic;using System.IO;using System.Linq;

すぐに解答を見るのではなく、まずは自分でコードを作成してから解答例と比較してみましょう。

1. C#演習問題を始める前に:学習目的とこの記事の使い方

1-1. C#演習で身につくスキルと到達目標

C#演習問題に繰り返し取り組むことで、次のようなスキルを身につけられます。

  • C#の基本文法を使って処理を組み立てる力

  • エラーメッセージから原因を特定する力

  • 処理をメソッドやクラスに分割する力

  • 配列やコレクションから必要なデータを取り出す力

  • 例外や不正入力を考慮した安全なコードを書く力

  • 商品、顧客、在庫などのデータを扱う力

最初の到達目標は、画面に文字を表示するだけのコードではなく、「入力を受け取り、条件に応じて処理し、結果を出力するプログラム」を自力で作れるようになることです。

その後は、メソッドやクラスを使って処理を整理し、複数のデータを扱う小規模なアプリケーションの作成を目指します。

1-2. 初心者が演習前に準備すべき開発環境

C#演習には、次のいずれかの開発環境が適しています。

  • Visual Studio

  • Visual Studio CodeとC#関連拡張機能

  • JetBrains Rider

  • ブラウザ上で実行できるC#実行環境

初心者には、プロジェクト作成、コード補完、デバッグ機能がまとまっているVisual Studioが使いやすいでしょう。

コンソールアプリを作成したら、まず次のコードが実行できることを確認します。

Console.WriteLine("Hello, C#!");

実行結果に「Hello, C#!」と表示されれば、演習を始める準備は完了です。

1-3. 演習問題100選のレベル別学習ロードマップ

本記事の演習問題は、次の順序で進めることを想定しています。

レベル問題番号主な学習内容
基礎1~20変数、型、入力、条件分岐、ループ
初級21~40数値計算、文字列、判定、定番アルゴリズム
中級41~70配列、List、Dictionary、メソッド、クラス
応用71~90例外処理、ファイル、日時、LINQ
実務想定91~100商品、顧客、在庫、売上、入力チェック

プログラミング未経験者は、問題1から順番に進めるのがおすすめです。ほかのプログラミング言語を学んだ経験がある場合は、問題を確認し、理解できない分野から取り組んでも構いません。

1-4. 解答を見る前に意識したい問題の解き方

問題を読んだら、すぐにコードを書き始めるのではなく、次の3点を整理します。

  1. 入力として何を受け取るか

  2. どのような手順で処理するか

  3. 最終的に何を出力するか

例えば、「整数が偶数か奇数かを判定する」という問題では、次のように整理できます。

  • 入力:整数

  • 処理:2で割った余りを求める

  • 出力:余りが0なら偶数、それ以外なら奇数

処理を日本語で説明できれば、コードにも変換しやすくなります。

2. C#の基礎文法を確認する演習問題

2-1. 変数・データ型・定数の演習問題

問題1:名前と年齢を変数に代入する

文字列型の変数nameと整数型の変数ageを作成し、名前と年齢を表示してください。

問題2:複数のデータ型を使う

商品名、価格、在庫の有無を、それぞれ適切なデータ型の変数に代入して表示してください。

問題3:定数を使って円周を計算する

円周率を定数として定義し、半径5の円周を求めてください。

問題4:整数を小数型へ変換する

整数型の値10double型へ変換して表示してください。

問題5:小数を整数へキャストする

12.8を整数型へ明示的にキャストし、結果を確認してください。

2-2. 文字列操作と数値計算の演習問題

問題6:文字列を連結する

姓と名を別々の変数に代入し、1つの文字列として表示してください。

問題7:文字列補間を使う

商品名と価格を変数に代入し、「商品名は○○、価格は○円です」と表示してください。

問題8:文字列の長さを求める

任意の文字列について、文字数を表示してください。

問題9:文字列の一部を取り出す

文字列"Programming"から"Program"を取り出してください。

問題10:長方形の面積を求める

幅8、高さ5の長方形の面積を計算してください。

2-3. 標準入力・標準出力の演習問題

問題11:名前を入力してあいさつする

コンソールから名前を受け取り、「こんにちは、○○さん」と表示してください。

問題12:2つの整数を入力して合計する

2つの整数を入力し、合計を表示してください。

問題13:安全に整数を入力する

int.TryParseを使い、入力が整数なら値を表示し、整数でなければエラーメッセージを表示してください。

2-4. if文・switch文による条件分岐の演習問題

問題14:正数・負数・ゼロを判定する

入力された整数が正数、負数、ゼロのどれであるか判定してください。

問題15:偶数・奇数を判定する

入力された整数が偶数か奇数かを判定してください。

問題16:点数から評価を表示する

点数が80点以上なら「A」、60点以上なら「B」、それ未満なら「C」と表示してください。

問題17:曜日番号を曜日名に変換する

1から7までの整数を受け取り、switch文で曜日を表示してください。

2-5. for文・while文による繰り返し処理の演習問題

問題18:1から10まで表示する

for文を使って、1から10までの整数を順番に表示してください。

問題19:カウントダウンする

while文を使って、10から1までの整数を表示してください。

2-6. 配列・Listの基本操作演習問題

問題20:配列とListを操作する

整数配列の全要素を表示した後、List<string>に3つの名前を追加して表示してください。

2-7. 基礎文法演習の解答・解説

問題1の解答

string name = "山田";int age = 25;

Console.WriteLine($"名前:{name}");Console.WriteLine($"年齢:{age}");

文字列にはstring、整数にはintを使用します。

問題2の解答

string productName = "ノートPC";decimal price = 98000m;bool isInStock = true;

Console.WriteLine($"商品名:{productName}");Console.WriteLine($"価格:{price}円");Console.WriteLine($"在庫あり:{isInStock}");

金額には誤差が生じにくいdecimalが適しています。decimalリテラルの末尾にはmを付けます。

問題3の解答

const double Pi = Math.PI;double radius = 5;double circumference = 2 * Pi * radius;

Console.WriteLine(circumference);

変更しない値はconstで定数として定義できます。

問題4の解答

int number = 10;double converted = number;

Console.WriteLine(converted);

intからdoubleへの変換では情報が失われないため、暗黙的に変換できます。

問題5の解答

double value = 12.8;int converted = (int)value;

Console.WriteLine(converted);

実行結果は12です。キャストでは小数部分が切り捨てられます。

問題6の解答

string lastName = "山田";string firstName = "太郎";string fullName = lastName + " " + firstName;

Console.WriteLine(fullName);

+演算子を使うと、文字列同士を連結できます。

問題7の解答

string productName = "キーボード";int price = 5000;

Console.WriteLine($"商品名は{productName}、価格は{price}円です");

文字列の先頭に$を付けると、波かっこ内に変数や式を埋め込めます。

問題8の解答

string text = "CSharp";Console.WriteLine(text.Length);

Lengthプロパティで文字数を取得できます。

問題9の解答

string text = "Programming";string result = text.Substring(0, 7);

Console.WriteLine(result);

Substring(開始位置, 文字数)で文字列の一部を取り出せます。インデックスは0から始まります。

問題10の解答

int width = 8;int height = 5;int area = width * height;

Console.WriteLine($"面積:{area}");

問題11の解答

Console.Write("名前を入力してください:");string name = Console.ReadLine() ?? "";

Console.WriteLine($"こんにちは、{name}さん");

Console.ReadLineの結果はnullになる可能性があるため、??を使って空文字列を補っています。

問題12の解答

Console.Write("1つ目の整数:");int first = int.Parse(Console.ReadLine() ?? "0");

Console.Write("2つ目の整数:");int second = int.Parse(Console.ReadLine() ?? "0");

Console.WriteLine($"合計:{first + second}");

int.Parseは、変換できない文字が入力されると例外を発生させます。実用的な処理ではTryParseの利用が安全です。

問題13の解答

Console.Write("整数を入力してください:");string input = Console.ReadLine() ?? "";

if (int.TryParse(input, out int number)){Console.WriteLine($"入力値:{number}");}else{Console.WriteLine("整数を入力してください。");}

TryParseは変換に成功するとtrue、失敗するとfalseを返します。

問題14の解答

int number = -3;

if (number > 0){Console.WriteLine("正数");}else if (number < 0){Console.WriteLine("負数");}else{Console.WriteLine("ゼロ");}

問題15の解答

int number = 7;

if (number % 2 == 0){Console.WriteLine("偶数");}else{Console.WriteLine("奇数");}

%は余りを求める演算子です。

問題16の解答

int score = 75;

if (score >= 80){Console.WriteLine("A");}else if (score >= 60){Console.WriteLine("B");}else{Console.WriteLine("C");}

条件は上位の範囲から判定します。

問題17の解答

int dayNumber = 3;

string dayName = dayNumber switch{1 => "月曜日",2 => "火曜日",3 => "水曜日",4 => "木曜日",5 => "金曜日",6 => "土曜日",7 => "日曜日",_ => "範囲外"};

Console.WriteLine(dayName);

_は、どの条件にも一致しなかった場合を表します。

問題18の解答

for (int i = 1; i <= 10; i++){Console.WriteLine(i);}

問題19の解答

int count = 10;

while (count >= 1){Console.WriteLine(count);count--;}

ループ内でcountを減らさないと無限ループになるため注意します。

問題20の解答

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

foreach (int number in numbers){Console.WriteLine(number);}

List<string> names = new(){"佐藤","鈴木","高橋"};

foreach (string name in names){Console.WriteLine(name);}

配列は基本的に要素数が固定ですが、List<T>は要素を追加・削除できます。

3. 初心者向けC#演習問題:基本処理を確実に習得する

3-1. 四則演算・平均値・最大値を求める問題

問題21:2つの数で四則演算する

2つの整数について、加算、減算、乗算、除算の結果を表示してください。

問題22:3科目の平均点を求める

国語、数学、英語の点数から平均点を求めてください。

問題23:3つの整数の最大値を求める

3つの整数を比較し、最大値を表示してください。

問題24:複数の整数の最小値を求める

整数配列から最小値を求めてください。

問題25:割引後の価格を計算する

商品の価格と割引率から、割引後の価格を求めてください。

3-2. 偶数・奇数・素数判定の問題

問題26:偶数・奇数を三項演算子で判定する

整数を受け取り、三項演算子を使って偶数または奇数と表示してください。

問題27:うるう年を判定する

西暦を入力し、うるう年かどうかを判定してください。

問題28:素数を判定する

2以上の整数を入力し、素数かどうかを判定してください。

問題29:最大公約数を求める

2つの正の整数について、ユークリッドの互除法で最大公約数を求めてください。

問題30:各桁の合計を求める

正の整数の各桁を合計してください。例えば1234なら結果は10です。

3-3. 文字数カウント・文字列反転の問題

問題31:空白を除いた文字数を数える

入力された文字列から空白を除き、残った文字数を求めてください。

問題32:指定した文字の出現回数を数える

文字列の中に、指定した文字が何回登場するか数えてください。

問題33:文字列を反転する

"CSharp""prahSC"のように逆順にしてください。

問題34:回文を判定する

前から読んでも後ろから読んでも同じ文字列か判定してください。

3-4. 九九表・三角形表示・FizzBuzzの問題

問題35:九九表を表示する

1×1から9×9までの計算結果を表形式で表示してください。

問題36:直角三角形を表示する

次のような図形を表示してください。

***



問題37:逆向きの三角形を表示する

次のような図形を表示してください。



***

問題38:FizzBuzzを実装する

1から100までの整数を表示し、3の倍数ではFizz、5の倍数ではBuzz、両方の倍数ではFizzBuzzと表示してください。

問題39:1からNまでの合計を求める

入力された正の整数Nについて、1からNまでの合計を求めてください。

問題40:階乗を求める

入力された0以上の整数について、階乗を求めてください。

3-5. 初心者向け演習の解答・解説

問題21の解答

double first = 10;double second = 4;

Console.WriteLine($"加算:{first + second}");Console.WriteLine($"減算:{first - second}");Console.WriteLine($"乗算:{first * second}");

if (second != 0){Console.WriteLine($"除算:{first / second}");}else{Console.WriteLine("0では除算できません。");}

除算する場合は、除数が0でないことを確認します。

問題22の解答

int japanese = 80;int math = 75;int english = 90;

double average = (japanese + math + english) / 3.0;Console.WriteLine($"平均点:{average:F1}");

3.0で割ることで、小数を含む結果になります。F1は小数第1位まで表示する書式指定です。

問題23の解答

int a = 15;int b = 28;int c = 21;

int max = a;

if (b > max){max = b;}

if (c > max){max = c;}

Console.WriteLine($"最大値:{max}");

Math.Maxを利用する場合は、次のようにも書けます。

int max = Math.Max(a, Math.Max(b, c));

問題24の解答

int[] numbers = { 8, 3, 12, -2, 6 };int min = numbers[0];

foreach (int number in numbers){if (number < min){min = number;}}

Console.WriteLine($"最小値:{min}");

最初の要素を暫定的な最小値として、順番に比較します。

問題25の解答

decimal price = 5000m;decimal discountRate = 20m;

decimal discountedPrice = price * (1 - discountRate / 100);Console.WriteLine($"割引後:{discountedPrice}円");

問題26の解答

int number = 17;string result = number % 2 == 0 ? "偶数" : "奇数";

Console.WriteLine(result);

三項演算子は、単純な条件によって値を切り替える場合に便利です。

問題27の解答

int year = 2028;

bool isLeapYear =year % 400 == 0 ||(year % 4 == 0 && year % 100 != 0);

Console.WriteLine(isLeapYear ? "うるう年" : "平年");

西暦が400で割り切れる年、または4で割り切れて100で割り切れない年がうるう年です。

標準ライブラリを使う場合は、次のように判定できます。

Console.WriteLine(DateTime.IsLeapYear(year));

問題28の解答

int number = 29;bool isPrime = number >= 2;

for (int i = 2; i * i <= number && isPrime; i++){if (number % i == 0){isPrime = false;}}

Console.WriteLine(isPrime ? "素数" : "素数ではない");

割る数は平方根まで調べれば十分です。

問題29の解答

int a = 48;int b = 18;

while (b != 0){int remainder = a % b;a = b;b = remainder;}

Console.WriteLine($"最大公約数:{a}");

余りが0になるまで「割る数」と「余り」を入れ替えます。

問題30の解答

int number = 1234;int sum = 0;

while (number > 0){sum += number % 10;number /= 10;}

Console.WriteLine($"各桁の合計:{sum}");

number % 10で末尾の数字を取得し、number /= 10で末尾を取り除きます。

問題31の解答

string text = "C# programming exercise";int count = 0;

foreach (char character in text){if (!char.IsWhiteSpace(character)){count++;}}

Console.WriteLine($"空白を除いた文字数:{count}");

問題32の解答

string text = "programming";char target = 'm';int count = 0;

foreach (char character in text){if (character == target){count++;}}

Console.WriteLine($"出現回数:{count}");

問題33の解答

string text = "CSharp";char[] characters = text.ToCharArray();

Array.Reverse(characters);

string reversed = new string(characters);Console.WriteLine(reversed);

問題34の解答

string text = "level";char[] characters = text.ToCharArray();

Array.Reverse(characters);

string reversed = new string(characters);bool isPalindrome = text.Equals(reversed,StringComparison.OrdinalIgnoreCase);

Console.WriteLine(isPalindrome ? "回文" : "回文ではない");

大文字と小文字を区別しない場合は、StringComparison.OrdinalIgnoreCaseを指定します。

問題35の解答

for (int row = 1; row <= 9; row++){for (int column = 1; column <= 9; column++){Console.Write($"{row * column,3}");}

Console.WriteLine();

}

ループを入れ子にすることで、行と列を処理できます。

問題36の解答

for (int row = 1; row <= 5; row++){for (int column = 1; column <= row; column++){Console.Write("*");}

Console.WriteLine();

}

問題37の解答

for (int row = 5; row >= 1; row--){for (int column = 1; column <= row; column++){Console.Write("*");}

Console.WriteLine();

}

問題38の解答

for (int number = 1; number <= 100; number++){if (number % 15 == 0){Console.WriteLine("FizzBuzz");}else if (number % 3 == 0){Console.WriteLine("Fizz");}else if (number % 5 == 0){Console.WriteLine("Buzz");}else{Console.WriteLine(number);}}

3と5の両方で割り切れる条件を最初に判定します。

問題39の解答

int n = 100;int sum = 0;

for (int i = 1; i <= n; i++){sum += i;}

Console.WriteLine($"合計:{sum}");

等差数列の公式を使う場合は、n * (n + 1) / 2でも計算できます。

問題40の解答

int number = 5;long factorial = 1;

for (int i = 2; i <= number; i++){factorial *= i;}

Console.WriteLine($"{number}! = {factorial}");

0の階乗は1です。大きな数ではlongでも範囲を超える点に注意してください。

4. 配列・コレクションを使ったC#演習問題

4-1. 配列の合計・平均・検索の問題

問題41:配列の合計を求める

整数配列の全要素を合計してください。

問題42:配列の平均を求める

整数配列の平均値を求めてください。

問題43:配列の最大値と最小値を求める

1回のループで最大値と最小値を求めてください。

問題44:指定した値を線形検索する

配列から指定した値を探し、見つかったインデックスを表示してください。

問題45:指定した値の出現回数を数える

整数配列の中に、指定した値が何回含まれているか数えてください。

問題46:配列の要素を逆順に並べる

標準のArray.Reverseを使わず、配列を逆順にしてください。

4-2. Listの追加・削除・並び替えの問題

問題47:Listに要素を追加する

空のList<string>を作り、3つの商品名を追加してください。

問題48:指定した要素を削除する

商品名のリストから、指定した商品を削除してください。

問題49:数値リストを昇順・降順に並べる

整数のリストを昇順と降順で表示してください。

問題50:重複した要素を削除する

文字列リストから重複した要素を取り除いてください。

4-3. Dictionaryを使ったデータ管理の問題

問題51:単語の出現回数を数える

複数の単語を含む配列から、各単語の出現回数をDictionaryで集計してください。

問題52:商品名と価格を管理する

商品名をキー、価格を値として登録し、指定商品の価格を表示してください。

4-4. foreachとLINQの基本演習問題

問題53:foreachで合格者を表示する

名前と点数を管理し、60点以上の人だけを表示してください。

問題54:LINQで偶数だけを抽出する

整数配列から偶数だけを取り出してください。

問題55:LINQで並び替えて合計する

整数のリストを降順に並べ、上位3件の合計を求めてください。

4-5. 配列・コレクション演習の解答・解説

問題41の解答

int[] numbers = { 10, 20, 30, 40 };int sum = 0;

foreach (int number in numbers){sum += number;}

Console.WriteLine($"合計:{sum}");

問題42の解答

int[] numbers = { 70, 80, 90 };int sum = 0;

foreach (int number in numbers){sum += number;}

double average = numbers.Length == 0? 0: (double)sum / numbers.Length;

Console.WriteLine($"平均:{average:F1}");

空配列では0除算が発生するため、要素数を確認します。

問題43の解答

int[] numbers = { 7, 2, 15, -4, 9 };

if (numbers.Length == 0){Console.WriteLine("配列が空です。");}else{int max = numbers[0];int min = numbers[0];

foreach (int number in numbers){if (number &gt; max){max = number;}if (number &lt; min){min = number;}}Console.WriteLine($"最大値:{max}");Console.WriteLine($"最小値:{min}");

}

問題44の解答

int[] numbers = { 4, 8, 15, 16, 23, 42 };int target = 16;int foundIndex = -1;

for (int i = 0; i < numbers.Length; i++){if (numbers[i] == target){foundIndex = i;break;}}

Console.WriteLine(foundIndex >= 0? $"インデックス{foundIndex}で見つかりました。": "見つかりませんでした。");

見つからなかったことを表す値として、一般的に-1を使います。

問題45の解答

int[] numbers = { 1, 3, 3, 5, 3, 7 };int target = 3;int count = 0;

foreach (int number in numbers){if (number == target){count++;}}

Console.WriteLine($"出現回数:{count}");

問題46の解答

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

for (int left = 0, right = numbers.Length - 1;left < right;left++, right--){(numbers[left], numbers[right]) =(numbers[right], numbers[left]);}

Console.WriteLine(string.Join(", ", numbers));

配列の両端から要素を交換していきます。

問題47の解答

List<string> products = new();

products.Add("マウス");products.Add("キーボード");products.Add("モニター");

Console.WriteLine(string.Join(", ", products));

問題48の解答

List<string> products = new(){"マウス","キーボード","モニター"};

bool removed = products.Remove("キーボード");

Console.WriteLine(removed? "商品を削除しました。": "商品が見つかりません。");

Console.WriteLine(string.Join(", ", products));

Removeは、削除できた場合にtrueを返します。

問題49の解答

List<int> numbers = new() { 5, 1, 8, 3, 2 };

numbers.Sort();Console.WriteLine($"昇順:{string.Join(", ", numbers)}");

numbers.Reverse();Console.WriteLine($"降順:{string.Join(", ", numbers)}");

問題50の解答

List<string> names = new(){"佐藤","鈴木","佐藤","高橋","鈴木"};

List<string> uniqueNames = new();

foreach (string name in names){if (!uniqueNames.Contains(name)){uniqueNames.Add(name);}}

Console.WriteLine(string.Join(", ", uniqueNames));

LINQを使う場合は、names.Distinct().ToList()でも重複を削除できます。

問題51の解答

string[] words ={"C#","Java","C#","Python","C#","Java"};

Dictionary<string, int> counts = new();

foreach (string word in words){if (counts.ContainsKey(word)){counts[word]++;}else{counts[word] = 1;}}

foreach (KeyValuePair<string, int> item in counts){Console.WriteLine($"{item.Key}:{item.Value}回");}

問題52の解答

Dictionary<string, decimal> prices = new(){["マウス"] = 3000m,["キーボード"] = 7000m,["モニター"] = 30000m};

string target = "キーボード";

if (prices.TryGetValue(target, out decimal price)){Console.WriteLine($"{target}:{price}円");}else{Console.WriteLine("商品が見つかりません。");}

値を取得する場合は、存在確認と取得を同時に行えるTryGetValueが便利です。

問題53の解答

Dictionary<string, int> scores = new(){["佐藤"] = 75,["鈴木"] = 55,["高橋"] = 82};

foreach (KeyValuePair<string, int> student in scores){if (student.Value >= 60){Console.WriteLine($"{student.Key}:{student.Value}点");}}

問題54の解答

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

IEnumerable<int> evenNumbers =numbers.Where(number => number % 2 == 0);

Console.WriteLine(string.Join(", ", evenNumbers));

Whereは、条件を満たす要素だけを抽出します。

問題55の解答

List<int> numbers = new(){10, 50, 20, 80, 40};

int total = numbers.OrderByDescending(number => number).Take(3).Sum();

Console.WriteLine($"上位3件の合計:{total}");

LINQでは処理を連結し、「並び替え、上位3件取得、合計」という流れを読みやすく表現できます。

5. メソッド・クラス・オブジェクト指向のC#演習問題

5-1. メソッドの作成と戻り値の演習問題

問題56:2つの整数を加算するメソッド

2つの整数を引数として受け取り、合計を返すAddメソッドを作成してください。

問題57:素数判定メソッド

整数を受け取り、素数ならtrueを返すIsPrimeメソッドを作成してください。

問題58:配列の最大値を返すメソッド

整数配列を受け取り、最大値を返すメソッドを作成してください。

5-2. 引数・オーバーロード・再帰処理の演習問題

問題59:省略可能な引数を使う

名前と敬称を受け取り、あいさつ文を返すメソッドを作成してください。敬称を省略した場合は「さん」を使用します。

問題60:面積計算メソッドをオーバーロードする

正方形と長方形の面積を求める同名メソッドを作成してください。

問題61:再帰で階乗を求める

再帰処理を使って階乗を求めるメソッドを作成してください。

問題62:再帰でフィボナッチ数を求める

指定した位置のフィボナッチ数を返すメソッドを作成してください。

5-3. クラス・プロパティ・コンストラクタの演習問題

問題63:Personクラスを作る

名前と年齢のプロパティを持ち、自己紹介を表示するPersonクラスを作成してください。

問題64:Productクラスにコンストラクタを作る

商品名、価格、在庫数を受け取るコンストラクタを作成してください。

問題65:BankAccountクラスを作る

入金、出金、残高表示ができる銀行口座クラスを作成してください。

5-4. 継承・抽象クラス・インターフェースの演習問題

問題66:Employeeクラスを継承する

従業員クラスを継承し、役職を持つManagerクラスを作成してください。

問題67:抽象クラスで図形を表現する

面積を求める抽象メソッドを持つShapeクラスと、円を表すCircleクラスを作成してください。

問題68:印刷用インターフェースを作る

Printメソッドを持つIPrintableインターフェースを定義し、請求書クラスに実装してください。

問題69:ポリモーフィズムで支払い処理を切り替える

共通の支払いインターフェースを使い、現金払いとクレジットカード払いを切り替えてください。

問題70:在庫を安全に管理するクラスを作る

在庫数を外部から直接変更できないようにし、入庫・出庫メソッドで管理してください。

5-5. オブジェクト指向演習の解答・解説

問題56の解答

static int Add(int first, int second){return first + second;}

int result = Add(10, 20);Console.WriteLine(result);

メソッドに分割すると、同じ処理を何度でも再利用できます。

問題57の解答

static bool IsPrime(int number){if (number < 2){return false;}

for (int i = 2; i * i &lt;= number; i++){if (number % i == 0){return false;}}return true;

}

Console.WriteLine(IsPrime(29));

判定結果をboolで返すメソッド名には、IsHasを付けると意図が伝わりやすくなります。

問題58の解答

static int GetMax(int[] numbers){if (numbers.Length == 0){throw new ArgumentException("配列に要素が必要です。",nameof(numbers));}

int max = numbers<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[0]</span>;foreach (int number in numbers){if (number &gt; max){max = number;}}return max;

}

Console.WriteLine(GetMax(new[] { 4, 9, 2, 7 }));

処理できない空配列が渡された場合は、例外によって呼び出し側へ知らせています。

問題59の解答

static string CreateGreeting(string name,string title = "さん"){return $"こんにちは、{name}{title}";}

Console.WriteLine(CreateGreeting("山田"));Console.WriteLine(CreateGreeting("佐藤", "先生"));

省略可能な引数は、必須の引数より後ろに定義します。

問題60の解答

static int CalculateArea(int side){return side * side;}

static int CalculateArea(int width, int height){return width * height;}

Console.WriteLine(CalculateArea(5));Console.WriteLine(CalculateArea(5, 8));

メソッド名が同じでも、引数の個数や型が異なれば複数定義できます。

問題61の解答

static long Factorial(int number){if (number < 0){throw new ArgumentOutOfRangeException(nameof(number));}

if (number &lt;= 1){return 1;}return number * Factorial(number - 1);

}

Console.WriteLine(Factorial(5));

再帰処理では、必ず処理を終了する条件が必要です。

問題62の解答

static long Fibonacci(int position){if (position < 0){throw new ArgumentOutOfRangeException(nameof(position));}

if (position &lt;= 1){return position;}return Fibonacci(position - 1)+ Fibonacci(position - 2);

}

Console.WriteLine(Fibonacci(10));

単純な再帰によるフィボナッチ計算は、同じ計算を何度も繰り返します。実務ではループやメモ化を検討します。

問題63の解答

public class Person{public string Name { get; set; } = "";public int Age { get; set; }

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

}

利用例は次のとおりです。

Person person = new(){Name = "山田太郎",Age = 25};

person.Introduce();

クラスはデータと関連する処理をまとめるために使います。

問題64の解答

public class Product{public string Name { get; }public decimal Price { get; }public int Stock { get; private set; }

public Product(string name,decimal price,int stock){Name = name;Price = price;Stock = stock;}

}

コンストラクタを利用すると、オブジェクト生成時に必要な値を必ず設定できます。

問題65の解答

public class BankAccount{public string OwnerName { get; }public decimal Balance { get; private set; }

public BankAccount(string ownerName,decimal initialBalance = 0){if (initialBalance &lt; 0){throw new ArgumentOutOfRangeException(nameof(initialBalance));}OwnerName = ownerName;Balance = initialBalance;}public void Deposit(decimal amount){if (amount &lt;= 0){throw new ArgumentOutOfRangeException(nameof(amount));}Balance += amount;}public bool Withdraw(decimal amount){if (amount &lt;= 0 || amount &gt; Balance){return false;}Balance -= amount;return true;}

}

残高の変更をメソッド経由に限定すると、不正な値を防ぎやすくなります。

問題66の解答

public class Employee{public string Name { get; }

public Employee(string name){Name = name;}public virtual void DisplayInfo(){Console.WriteLine($"従業員:{Name}");}

}

public class Manager : Employee{public string Department { get; }

public Manager(string name,string department) : base(name){Department = department;}public override void DisplayInfo(){Console.WriteLine($"管理職:{Name}、部署:{Department}");}

}

baseを使うと、基底クラスのコンストラクタを呼び出せます。

問題67の解答

public abstract class Shape{public abstract double GetArea();}

public class Circle : Shape{public double Radius { get; }

public Circle(double radius){if (radius &lt;= 0){throw new ArgumentOutOfRangeException(nameof(radius));}Radius = radius;}public override double GetArea(){return Math.PI * Radius * Radius;}

}

抽象クラスは、共通の概念を表しながら、具体的な処理を派生クラスに任せたい場合に使用します。

問題68の解答

public interface IPrintable{void Print();}

public class Invoice : IPrintable{public string CustomerName { get; }public decimal Amount { get; }

public Invoice(string customerName,decimal amount){CustomerName = customerName;Amount = amount;}public void Print(){Console.WriteLine($"請求先:{CustomerName}");Console.WriteLine($"請求額:{Amount}円");}

}

インターフェースは、異なるクラスに共通の操作を持たせたい場合に適しています。

問題69の解答

public interface IPayment{void Pay(decimal amount);}

public class CashPayment : IPayment{public void Pay(decimal amount){Console.WriteLine($"現金で{amount}円を支払いました。");}}

public class CreditCardPayment : IPayment{public void Pay(decimal amount){Console.WriteLine($"カードで{amount}円を支払いました。");}}

利用例は次のとおりです。

static void ProcessPayment(IPayment payment,decimal amount){payment.Pay(amount);}

ProcessPayment(new CashPayment(), 3000m);ProcessPayment(new CreditCardPayment(), 5000m);

呼び出し側は具体的な支払い方法を意識せず、IPaymentとして処理できます。

問題70の解答

public class InventoryItem{public string Name { get; }public int Stock { get; private set; }

public InventoryItem(string name,int initialStock){if (initialStock &lt; 0){throw new ArgumentOutOfRangeException(nameof(initialStock));}Name = name;Stock = initialStock;}public void Receive(int quantity){if (quantity &lt;= 0){throw new ArgumentOutOfRangeException(nameof(quantity));}Stock += quantity;}public bool Ship(int quantity){if (quantity &lt;= 0 || quantity &gt; Stock){return false;}Stock -= quantity;return true;}

}

プロパティのsetprivateにすることで、外部から在庫数を直接変更できなくしています。

6. 例外処理・ファイル操作・日時処理のC#演習問題

6-1. try-catchを使った例外処理の問題

問題71:0除算の例外を処理する

2つの整数を入力して除算し、0で割ろうとした場合にエラーメッセージを表示してください。

問題72:不正な数値入力を処理する

入力値を整数へ変換し、変換できない場合に再入力を求めてください。

問題73:独自例外を作る

在庫不足を表すInsufficientStockExceptionを作成してください。

6-2. ファイル読み込み・書き込みの問題

問題74:テキストファイルへ書き込む

複数行の文字列をテキストファイルへ保存してください。

問題75:テキストファイルを読み込む

テキストファイルを1行ずつ読み込み、行番号付きで表示してください。

問題76:ログを追記する

現在日時とメッセージをログファイルへ追記してください。

6-3. CSVデータを扱う演習問題

問題77:CSVファイルを読み込む

商品ID、商品名、価格を含むCSVファイルを読み込み、各データを表示してください。

問題78:CSVの売上金額を集計する

商品名、単価、数量を含むCSVデータから売上合計を求めてください。

6-4. DateTimeを使った日付計算の問題

問題79:指定日までの日数を求める

今日から指定日までの日数を計算してください。

問題80:誕生日から年齢を求める

生年月日と基準日から満年齢を求めてください。

6-5. 実務で使う基本処理の解答・解説

問題71の解答

try{Console.Write("割られる数:");int dividend = int.Parse(Console.ReadLine() ?? "");

Console.Write("割る数:");int divisor = int.Parse(Console.ReadLine() ?? "");int result = dividend / divisor;Console.WriteLine($"結果:{result}");

}catch (FormatException){Console.WriteLine("整数を入力してください。");}catch (DivideByZeroException){Console.WriteLine("0では割れません。");}

発生する可能性がある例外ごとに処理を分けると、利用者へ適切なメッセージを表示できます。

問題72の解答

int number;

while (true){Console.Write("整数を入力してください:");string input = Console.ReadLine() ?? "";

if (int.TryParse(input, out number)){break;}Console.WriteLine("入力が正しくありません。");

}

Console.WriteLine($"入力値:{number}");

入力値の変換では、例外を捕捉するよりTryParseを使うほうが簡潔です。

問題73の解答

public class InsufficientStockException: Exception{public InsufficientStockException(){}

public InsufficientStockException(string message) : base(message){}public InsufficientStockException(string message,Exception innerException) : base(message, innerException){}

}

在庫不足時には、次のように例外を発生させます。

if (quantity > stock){throw new InsufficientStockException($"在庫が不足しています。在庫数:{stock}");}

独自例外を使うと、呼び出し側がエラーの種類を明確に判別できます。

問題74の解答

string path = "message.txt";

string[] lines ={"C#演習問題","ファイル書き込みの練習","3行目の文章"};

File.WriteAllLines(path, lines);

Console.WriteLine("ファイルへ書き込みました。");

WriteAllLinesは、文字列配列の各要素を1行として保存します。

問題75の解答

string path = "message.txt";

if (!File.Exists(path)){Console.WriteLine("ファイルが見つかりません。");}else{string[] lines = File.ReadAllLines(path);

for (int i = 0; i &lt; lines.Length; i++){Console.WriteLine($"{i + 1}: {lines<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[i]</span>}");}

}

ファイルを読み込む前に、File.Existsで存在を確認しています。

問題76の解答

static void WriteLog(string path,string message){string log =$"{DateTime.Now:yyyy-MM-dd HH:mm:ss}"+ $" {message}{Environment.NewLine}";

File.AppendAllText(path, log);

}

WriteLog("application.log", "処理を開始しました。");

AppendAllTextは既存の内容を消さず、末尾へ文字列を追加します。

問題77の解答

CSVファイルの内容を次のようにします。

1,マウス,30002,キーボード,70003,モニター,30000

読み込みコードは次のとおりです。

string path = "products.csv";

foreach (string line in File.ReadLines(path)){string[] columns = line.Split(',');

if (columns.Length != 3){Console.WriteLine($"形式が不正です:{line}");continue;}if (!int.TryParse(columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[0]</span>, out int id) ||!decimal.TryParse(columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[2]</span>,out decimal price)){Console.WriteLine($"値が不正です:{line}");continue;}string name = columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[1]</span>;Console.WriteLine($"ID:{id}、商品:{name}、価格:{price}円");

}

単純なSplitでは、値の中にカンマや改行を含む本格的なCSVを正確に処理できません。実務ではCSV対応ライブラリの利用を検討します。

問題78の解答

CSVファイルの内容を次のようにします。

マウス,3000,2キーボード,7000,1モニター,30000,3
decimal totalSales = 0;

foreach (string line in File.ReadLines("sales.csv")){string[] columns = line.Split(',');

if (columns.Length != 3){continue;}bool validPrice = decimal.TryParse(columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[1]</span>,out decimal unitPrice);bool validQuantity = int.TryParse(columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[2]</span>,out int quantity);if (!validPrice ||!validQuantity ||unitPrice &lt; 0 ||quantity &lt; 0){continue;}decimal lineTotal = unitPrice * quantity;totalSales += lineTotal;Console.WriteLine($"{columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[0]</span>}:{lineTotal}円");

}

Console.WriteLine($"売上合計:{totalSales}円");

問題79の解答

DateTime today = DateTime.Today;DateTime targetDate = new(2026, 12, 31);

int days = (targetDate - today).Days;

if (days >= 0){Console.WriteLine($"指定日まであと{days}日です。");}else{Console.WriteLine($"指定日から{-days}日経過しています。");}

DateTime同士を引くと、差を表すTimeSpanを取得できます。

問題80の解答

static int CalculateAge(DateTime birthDate,DateTime baseDate){int age = baseDate.Year - birthDate.Year;

if (birthDate.Date &gt; baseDate.AddYears(-age)){age--;}return age;

}

DateTime birthday = new(2000, 10, 15);DateTime today = DateTime.Today;

Console.WriteLine($"年齢:{CalculateAge(birthday, today)}歳");

単純に西暦を引くだけでは、今年の誕生日を迎えていない場合に1歳多くなるため補正します。

7. LINQ・ラムダ式を使った実践的C#演習問題

7-1. Where・Select・OrderByの基本演習問題

問題81:Whereで偶数を抽出する

1から20までの整数から、偶数だけを取り出してください。

問題82:Selectで数値を2乗する

整数リストの各要素を2乗した新しいリストを作成してください。

問題83:文字列を長さ順に並べる

複数の単語を、文字数が短い順に並べてください。

7-2. GroupBy・Count・Sumを使った集計問題

問題84:単語を先頭文字でグループ化する

英単語のリストを、先頭文字ごとにグループ化してください。

問題85:カテゴリ別の売上を集計する

売上データをカテゴリごとにまとめ、件数と合計金額を表示してください。

7-3. Listや配列から条件に合うデータを抽出する問題

問題86:価格範囲で商品を抽出する

商品リストから、価格が5,000円以上10,000円以下の商品を抽出してください。

問題87:条件に合う最初の商品を取得する

在庫がある商品のうち、最初の1件を取得してください。

問題88:AnyとAllで条件を判定する

在庫切れの商品が1件以上あるか、すべての商品価格が正の値かを判定してください。

7-4. オブジェクトの一覧をLINQで処理する問題

問題89:必要なプロパティだけを取り出す

顧客一覧から、顧客名とメールアドレスだけを取り出してください。

問題90:担当者別の売上ランキングを作る

売上データを担当者別に集計し、合計金額が高い順に表示してください。

7-5. LINQ演習の解答・解説

問題81の解答

IEnumerable<int> evenNumbers =Enumerable.Range(1, 20).Where(number => number % 2 == 0);

Console.WriteLine(string.Join(", ", evenNumbers));

Enumerable.Range(開始値, 要素数)で連続した整数を生成できます。

問題82の解答

List<int> numbers = new(){1, 2, 3, 4, 5};

List<int> squares = numbers.Select(number => number * number).ToList();

Console.WriteLine(string.Join(", ", squares));

Selectは、各要素を別の値へ変換します。

問題83の解答

string[] words ={"CSharp","Java","Go","Python"};

IEnumerable<string> orderedWords = words.OrderBy(word => word.Length).ThenBy(word => word);

Console.WriteLine(string.Join(", ", orderedWords));

文字数が同じ場合は、ThenByでさらに並び順を指定できます。

問題84の解答

string[] words ={"apple","ant","banana","book","cat"};

var groups = words.GroupBy(word => word[0]).OrderBy(group => group.Key);

foreach (var group in groups){Console.WriteLine($"{group.Key}: {string.Join(", ", group)}");}

GroupByは、指定したキーが同じ要素をまとめます。

問題85の解答

public record Sale(string Category,decimal Amount);

List<Sale> sales = new(){new("PC", 100000m),new("周辺機器", 5000m),new("PC", 120000m),new("周辺機器", 8000m)};

var summaries = sales.GroupBy(sale => sale.Category).Select(group => new{Category = group.Key,Count = group.Count(),Total = group.Sum(sale => sale.Amount)});

foreach (var summary in summaries){Console.WriteLine($"{summary.Category}:"+ $"{summary.Count}件、"+ $"{summary.Total}円");}

集計結果専用のデータを一時的に作る場合は、匿名型が便利です。

問題86の解答

public record Product(string Name,decimal Price,int Stock);

List<Product> products = new(){new("マウス", 3000m, 10),new("キーボード", 7000m, 5),new("Webカメラ", 9000m, 3),new("モニター", 30000m, 2)};

IEnumerable<Product> results = products.Where(product =>product.Price >= 5000m &&product.Price <= 10000m);

foreach (Product product in results){Console.WriteLine($"{product.Name}:{product.Price}円");}

問題87の解答

Product? product = products.FirstOrDefault(item => item.Stock > 0);

if (product is not null){Console.WriteLine(product.Name);}else{Console.WriteLine("在庫のある商品はありません。");}

FirstOrDefaultは、該当する要素がない場合に既定値を返します。参照型では通常nullとなるため、確認が必要です。

問題88の解答

bool hasOutOfStock =products.Any(product => product.Stock == 0);

bool allPricesArePositive =products.All(product => product.Price > 0);

Console.WriteLine($"在庫切れあり:{hasOutOfStock}");

Console.WriteLine($"すべて正しい価格:{allPricesArePositive}");

Anyは1件でも条件を満たすか、Allは全件が条件を満たすかを判定します。

問題89の解答

public record Customer(int Id,string Name,string Email,string Address);

List<Customer> customers = new(){new(1,"山田太郎","taro@example.com","東京都"),new(2,"佐藤花子","hanako@example.com","大阪府")};

var contacts = customers.Select(customer => new{customer.Name,customer.Email});

foreach (var contact in contacts){Console.WriteLine($"{contact.Name}:{contact.Email}");}

必要なデータだけを取り出すことで、画面表示やデータ転送に適した形へ変換できます。

問題90の解答

public record SalesRecord(string StaffName,decimal Amount);

List<SalesRecord> salesRecords = new(){new("山田", 50000m),new("佐藤", 30000m),new("山田", 80000m),new("鈴木", 120000m),new("佐藤", 70000m)};

var ranking = salesRecords.GroupBy(record => record.StaffName).Select(group => new{StaffName = group.Key,Total = group.Sum(record => record.Amount)}).OrderByDescending(item => item.Total);

int rank = 1;

foreach (var item in ranking){Console.WriteLine($"{rank}位:{item.StaffName} "+ $"{item.Total}円");

rank++;

}

「グループ化、集計、並び替え」は、業務データを扱う際によく使うLINQの組み合わせです。

8. 実務レベルに近づくC#演習問題

8-1. 商品管理システムの演習問題

問題91:商品を登録して一覧表示する

商品ID、商品名、価格、在庫数を持つ商品クラスを作り、複数の商品を登録して一覧表示してください。

問題92:商品IDまたは商品名で検索する

登録済みの商品から、商品IDまたは商品名に一致する商品を検索してください。

8-2. 顧客情報管理の演習問題

問題93:顧客情報を検証して登録する

顧客名、メールアドレス、電話番号を受け取り、必須項目を確認して登録してください。

問題94:顧客情報を更新する

顧客IDを指定し、メールアドレスと電話番号を更新してください。

8-3. 在庫数・売上金額を計算する演習問題

問題95:入庫と出庫を管理する

商品ごとに入庫・出庫を行い、現在の在庫数を表示してください。

問題96:在庫が少ない商品を抽出する

在庫数が安全在庫数以下の商品を一覧表示してください。

問題97:売上小計・消費税・合計金額を計算する

複数の注文明細から小計、消費税、税込合計を求めてください。

問題98:注文CSVを読み込んで集計する

注文データをCSVファイルから読み込み、顧客別の注文合計を表示してください。

8-4. 入力チェックとエラーハンドリングの演習問題

問題99:商品登録の入力値を検証する

商品名の未入力、0以下の価格、負の在庫数を検出し、すべてのエラーメッセージを表示してください。

問題100:簡易在庫・売上管理アプリを作る

商品登録、一覧、入庫、販売、売上表示の機能を持つコンソールアプリを作成してください。

8-5. 実務想定演習の解答・解説

問題91の解答

public class ManagedProduct{public int Id { get; }public string Name { get; }public decimal Price { get; }public int Stock { get; private set; }

public ManagedProduct(int id,string name,decimal price,int stock){Id = id;Name = name;Price = price;Stock = stock;}

}

List<ManagedProduct> products = new(){new(1, "マウス", 3000m, 10),new(2, "キーボード", 7000m, 5),new(3, "モニター", 30000m, 2)};

foreach (ManagedProduct product in products){Console.WriteLine($"ID:{product.Id}、"+ $"商品名:{product.Name}、"+ $"価格:{product.Price}円、"+ $"在庫:{product.Stock}");}

商品をクラスとして表現すると、関連する値を1つのオブジェクトにまとめられます。

問題92の解答

static ManagedProduct? FindProduct(IEnumerable<ManagedProduct> products,string keyword){if (int.TryParse(keyword, out int id)){ManagedProduct? byId =products.FirstOrDefault(product => product.Id == id);

    if (byId is not null){return byId;}}return products.FirstOrDefault(product =&gt;product.Name.Contains(keyword,StringComparison.OrdinalIgnoreCase));

}

Console.Write("商品IDまたは商品名:");string keyword = Console.ReadLine() ?? "";

ManagedProduct? product =FindProduct(products, keyword);

Console.WriteLine(product is null? "商品が見つかりません。": $"{product.Name}:{product.Price}円");

部分一致検索では、同じ名前を含む商品が複数存在する可能性も考慮します。

問題93の解答

public class ManagedCustomer{public int Id { get; }public string Name { get; }public string Email { get; }public string PhoneNumber { get; }

public ManagedCustomer(int id,string name,string email,string phoneNumber){Id = id;Name = name;Email = email;PhoneNumber = phoneNumber;}

}

static List<string> ValidateCustomer(string name,string email,string phoneNumber){List<string> errors = new();

if (string.IsNullOrWhiteSpace(name)){errors.Add("顧客名を入力してください。");}if (string.IsNullOrWhiteSpace(email) ||!email.Contains('@')){errors.Add("正しいメールアドレスを入力してください。");}if (string.IsNullOrWhiteSpace(phoneNumber)){errors.Add("電話番号を入力してください。");}return errors;

}

string name = "山田太郎";string email = "taro@example.com";string phoneNumber = "09012345678";

List<string> errors = ValidateCustomer(name,email,phoneNumber);

if (errors.Count > 0){foreach (string error in errors){Console.WriteLine(error);}}else{ManagedCustomer customer = new(1,name,email,phoneNumber);

Console.WriteLine($"{customer.Name}を登録しました。");

}

メールアドレスの厳密な検証は複雑です。実務では要件に応じた検証方法を採用します。

問題94の解答

更新可能な顧客クラスを用意します。

public class EditableCustomer{public int Id { get; }public string Name { get; }public string Email { get; private set; }public string PhoneNumber { get; private set; }

public EditableCustomer(int id,string name,string email,string phoneNumber){Id = id;Name = name;Email = email;PhoneNumber = phoneNumber;}public void UpdateContact(string email,string phoneNumber){if (string.IsNullOrWhiteSpace(email) ||!email.Contains('@')){throw new ArgumentException("メールアドレスが不正です。",nameof(email));}if (string.IsNullOrWhiteSpace(phoneNumber)){throw new ArgumentException("電話番号が不正です。",nameof(phoneNumber));}Email = email;PhoneNumber = phoneNumber;}

}

List<EditableCustomer> customers = new(){new(1,"山田太郎","old@example.com","0311112222")};

int targetId = 1;

EditableCustomer? customer =customers.FirstOrDefault(item => item.Id == targetId);

if (customer is null){Console.WriteLine("顧客が見つかりません。");}else{try{customer.UpdateContact("new@example.com","09012345678");

    Console.WriteLine("顧客情報を更新しました。");}catch (ArgumentException exception){Console.WriteLine(exception.Message);}

}

問題95の解答

public class StockProduct{public int Id { get; }public string Name { get; }public int Stock { get; private set; }

public StockProduct(int id,string name,int initialStock){if (initialStock &lt; 0){throw new ArgumentOutOfRangeException(nameof(initialStock));}Id = id;Name = name;Stock = initialStock;}public void Receive(int quantity){if (quantity &lt;= 0){throw new ArgumentOutOfRangeException(nameof(quantity));}Stock += quantity;}public void Ship(int quantity){if (quantity &lt;= 0){throw new ArgumentOutOfRangeException(nameof(quantity));}if (quantity &gt; Stock){throw new InsufficientStockException($"「{Name}」の在庫が不足しています。");}Stock -= quantity;}

}

StockProduct product = new(1,"キーボード",10);

product.Receive(5);product.Ship(3);

Console.WriteLine($"現在の在庫:{product.Stock}");

在庫を変更する処理をクラス内に集約することで、負の在庫が発生するリスクを減らせます。

問題96の解答

public record InventoryStatus(string ProductName,int Stock,int SafetyStock);

List<InventoryStatus> inventory = new(){new("マウス", 10, 5),new("キーボード", 3, 5),new("モニター", 2, 2)};

IEnumerable<InventoryStatus> alerts =inventory.Where(item =>item.Stock <= item.SafetyStock);

foreach (InventoryStatus item in alerts){Console.WriteLine($"{item.ProductName}:"+ $"在庫{item.Stock}、"+ $"安全在庫{item.SafetyStock}");}

安全在庫は、欠品を防ぐために確保しておきたい最低限の在庫数です。

問題97の解答

public record OrderLine(string ProductName,decimal UnitPrice,int Quantity){public decimal Subtotal =>UnitPrice * Quantity;}
List<OrderLine> orderLines = new(){new("マウス", 3000m, 2),new("キーボード", 7000m, 1),new("モニター", 30000m, 1)};

decimal subtotal = orderLines.Sum(line => line.Subtotal);

decimal taxRate = 0.10m;decimal tax = Math.Floor(subtotal * taxRate);

decimal total = subtotal + tax;

Console.WriteLine($"小計:{subtotal}円");Console.WriteLine($"消費税:{tax}円");Console.WriteLine($"合計:{total}円");

端数処理は業務ルールによって異なります。切り捨て、切り上げ、四捨五入のどれを使うか確認する必要があります。

問題98の解答

CSVファイルの内容を次のようにします。

1001,山田太郎,30001002,佐藤花子,70001003,山田太郎,50001004,鈴木一郎,12000
public record CustomerOrder(int OrderId,string CustomerName,decimal Amount);
List<CustomerOrder> orders = new();

foreach (string line in File.ReadLines("orders.csv")){string[] columns = line.Split(',');

if (columns.Length != 3){Console.WriteLine($"列数が不正です:{line}");continue;}bool validId = int.TryParse(columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[0]</span>,out int orderId);bool validAmount = decimal.TryParse(columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[2]</span>,out decimal amount);if (!validId || !validAmount || amount &lt; 0){Console.WriteLine($"データが不正です:{line}");continue;}orders.Add(new CustomerOrder(orderId,columns<span data-placeholder-token="true" class="text-token-text-primary cursor-text rounded-sm" style="background-color: color-mix(in srgb, var(--theme-user-selection-bg, var(--selection)) 30%, transparent); padding-top: 4px; padding-bottom: 4px;">[1]</span>,amount));

}

var totals = orders.GroupBy(order => order.CustomerName).Select(group => new{CustomerName = group.Key,Total = group.Sum(order => order.Amount)}).OrderByDescending(item => item.Total);

foreach (var item in totals){Console.WriteLine($"{item.CustomerName}:{item.Total}円");}

ファイル読み込み、入力検証、オブジェクト変換、集計という一連の処理を練習できます。

問題99の解答

static List<string> ValidateProduct(string name,decimal price,int stock){List<string> errors = new();

if (string.IsNullOrWhiteSpace(name)){errors.Add("商品名を入力してください。");}if (price &lt;= 0){errors.Add("価格は1円以上にしてください。");}if (stock &lt; 0){errors.Add("在庫数を負の値にはできません。");}return errors;

}

List<string> errors = ValidateProduct("",0,-1);

if (errors.Count == 0){Console.WriteLine("商品を登録できます。");}else{Console.WriteLine("入力内容を確認してください。");

foreach (string error in errors){Console.WriteLine($"・{error}");}

}

最初のエラーだけで処理を終了せず、すべてのエラーをまとめて表示すると、利用者が一度に修正できます。

問題100の解答

商品クラスを定義します。

public class StoreProduct{public int Id { get; }public string Name { get; }public decimal Price { get; }public int Stock { get; private set; }

public StoreProduct(int id,string name,decimal price,int stock){if (string.IsNullOrWhiteSpace(name)){throw new ArgumentException("商品名は必須です。",nameof(name));}if (price &lt;= 0){throw new ArgumentOutOfRangeException(nameof(price));}if (stock &lt; 0){throw new ArgumentOutOfRangeException(nameof(stock));}Id = id;Name = name;Price = price;Stock = stock;}public void Receive(int quantity){if (quantity &lt;= 0){throw new ArgumentOutOfRangeException(nameof(quantity));}Stock += quantity;}public decimal Sell(int quantity){if (quantity &lt;= 0){throw new ArgumentOutOfRangeException(nameof(quantity));}if (quantity &gt; Stock){throw new InsufficientStockException("在庫が不足しています。");}Stock -= quantity;return Price * quantity;}

}

メニュー処理は次のように実装できます。

List<StoreProduct> products = new();decimal totalSales = 0;int nextId = 1;

while (true){Console.WriteLine();Console.WriteLine("1:商品登録");Console.WriteLine("2:商品一覧");Console.WriteLine("3:入庫");Console.WriteLine("4:販売");Console.WriteLine("5:売上表示");Console.WriteLine("0:終了");Console.Write("選択:");

string command = Console.ReadLine() ?? "";try{switch (command){case "1":{Console.Write("商品名:");string name =Console.ReadLine() ?? "";Console.Write("価格:");if (!decimal.TryParse(Console.ReadLine(),out decimal price)){Console.WriteLine("価格が不正です。");break;}Console.Write("初期在庫:");if (!int.TryParse(Console.ReadLine(),out int stock)){Console.WriteLine("在庫数が不正です。");break;}products.Add(new StoreProduct(nextId++,name,price,stock));Console.WriteLine("商品を登録しました。");break;}case "2":{if (products.Count == 0){Console.WriteLine("商品がありません。");break;}foreach (StoreProduct productin products){Console.WriteLine($"ID:{product.Id}、"+ $"{product.Name}、"+ $"{product.Price}円、"+ $"在庫:{product.Stock}");}break;}case "3":{StoreProduct? product =ReadProduct(products);if (product is null){break;}Console.Write("入庫数:");if (!int.TryParse(Console.ReadLine(),out int quantity)){Console.WriteLine("数量が不正です。");break;}product.Receive(quantity);Console.WriteLine($"入庫後在庫:{product.Stock}");break;}case "4":{StoreProduct? product =ReadProduct(products);if (product is null){break;}Console.Write("販売数:");if (!int.TryParse(Console.ReadLine(),out int quantity)){Console.WriteLine("数量が不正です。");break;}decimal sales =product.Sell(quantity);totalSales += sales;Console.WriteLine($"販売額:{sales}円");break;}case "5":Console.WriteLine($"累計売上:{totalSales}円");break;case "0":return;default:Console.WriteLine("メニュー番号が不正です。");break;}}catch (ArgumentException exception){Console.WriteLine($"入力エラー:{exception.Message}");}catch (InsufficientStockException exception){Console.WriteLine($"在庫エラー:{exception.Message}");}

}

商品を読み取るメソッドを追加します。

static StoreProduct? ReadProduct(List<StoreProduct> products){Console.Write("商品ID:");

if (!int.TryParse(Console.ReadLine(),out int productId)){Console.WriteLine("商品IDが不正です。");return null;}StoreProduct? product =products.FirstOrDefault(item =&gt; item.Id == productId);if (product is null){Console.WriteLine("商品が見つかりません。");}return product;

}

この演習では、クラス、コレクション、入力チェック、例外処理、検索、在庫計算、売上計算を組み合わせています。さらに発展させる場合は、データのファイル保存、商品削除、販売履歴、売上集計などを追加してみましょう。

9. C#演習問題100選の一覧表

9-1. 初級レベルの演習問題一覧

問題演習内容主な学習項目
1名前と年齢の表示変数
2複数のデータ型string、decimal、bool
3円周の計算定数
4intからdoubleへの変換暗黙的変換
5doubleからintへの変換キャスト
6姓名の連結文字列連結
7商品情報の表示文字列補間
8文字数の取得Length
9文字列の切り出しSubstring
10長方形の面積乗算
11名前入力とあいさつConsole.ReadLine
122数の合計Parse
13安全な数値入力TryParse
14正数・負数・ゼロ判定if
15偶数・奇数判定剰余
16点数評価else if
17曜日変換switch
181から10の表示for
19カウントダウンwhile
20配列とListの表示foreach
21四則演算演算子
22平均点型変換
23最大値比較
24最小値配列走査
25割引計算割合
26三項演算子で偶奇判定三項演算子
27うるう年判定複合条件
28素数判定ループ
29最大公約数ユークリッドの互除法
30各桁の合計除算、剰余
31空白を除く文字数char
32文字の出現回数文字比較
33文字列反転char配列
34回文判定文字列比較
35九九表二重ループ
36直角三角形二重ループ
37逆三角形デクリメント
38FizzBuzz条件分岐
391からNまでの合計累積処理
40階乗繰り返し計算

9-2. 中級レベルの演習問題一覧

問題演習内容主な学習項目
41配列の合計配列
42配列の平均要素数
43最大値と最小値走査
44線形検索インデックス
45出現回数カウント
46配列反転要素交換
47Listへの追加Add
48Listから削除Remove
49Listの並び替えSort、Reverse
50重複削除Contains
51単語数集計Dictionary
52商品価格管理TryGetValue
53合格者抽出foreach
54偶数抽出Where
55上位3件の合計OrderBy、Take、Sum
56加算メソッド戻り値
57素数判定メソッドboolメソッド
58最大値メソッド配列引数
59あいさつメソッド省略可能引数
60面積計算オーバーロード
61再帰による階乗再帰
62フィボナッチ数再帰
63Personクラスクラス、プロパティ
64Productクラスコンストラクタ
65銀行口座カプセル化
66Managerクラス継承
67図形クラス抽象クラス
68請求書印刷インターフェース
69支払い処理ポリモーフィズム
70在庫管理クラスprivate set
710除算処理try-catch
72数値の再入力TryParse
73在庫不足例外独自例外
74ファイル書き込みWriteAllLines
75ファイル読み込みReadAllLines
76ログ追記AppendAllText
77商品CSV読み込みSplit
78CSV売上集計ファイル、計算
79指定日までの日数DateTime、TimeSpan
80年齢計算日付比較
81偶数抽出Where
82数値の2乗Select
83文字数順の並び替えOrderBy
84先頭文字別グループGroupBy
85カテゴリ別集計Count、Sum
86価格範囲検索複合条件
87最初の商品取得FirstOrDefault
88条件判定Any、All
89顧客情報の変換射影
90売上ランキングGroupBy、OrderByDescending

9-3. 実務レベルの演習問題一覧

問題演習内容主な学習項目
91商品登録と一覧エンティティ設計
92商品検索ID検索、部分一致
93顧客登録入力検証
94顧客情報更新更新処理
95入庫・出庫在庫トランザクション
96在庫アラート条件抽出
97税込金額計算金額、端数処理
98顧客別注文集計CSV、LINQ
99商品入力チェック複数エラー
100在庫・売上管理アプリ総合演習

9-4. 分野別に選べるC#演習問題一覧

分野対象問題
変数・データ型1~5
文字列・計算6~10、21~25、30~34
入出力11~13
条件分岐14~17、26~29、38
繰り返し18~19、35~40
配列・List20、41~50
Dictionary51~53
メソッド56~62
クラス・オブジェクト指向63~70
例外処理71~73
ファイル・CSV74~78、98
日時処理79~80
LINQ54~55、81~90、96
実務想定91~100

9-5. 学習目的別おすすめ演習問題

C#の基本文法を短期間で復習したい場合は、問題1~20に取り組みましょう。条件分岐やループを使った処理を強化したい場合は、問題21~40が適しています。

配列やコレクションの操作に慣れたい場合は、問題41~55を重点的に解きます。オブジェクト指向が苦手な場合は、問題56~70を順番に進め、メソッドからクラス、継承、インターフェースへ段階的に学びましょう。

業務データの加工や集計を学びたい場合は、問題71~90が適しています。転職用のポートフォリオや実務に近い練習を重視する場合は、問題91~100を発展させてください。

10. C#演習でよくあるつまずきと解決方法

10-1. エラー文の読み方がわからないときの対処法

C#のエラーメッセージには、通常、次の情報が含まれています。

  • エラーコード

  • エラーの内容

  • 発生したファイル

  • 行番号

  • 列番号

エラーが複数表示された場合は、最初のエラーから確認します。1つの構文エラーが原因で、その後の行にも連続してエラーが表示されることがあるためです。

例えば、セミコロンの付け忘れ、波かっこの閉じ忘れ、変数名の入力間違いを最初に確認しましょう。

実行時に例外が発生した場合は、例外の種類、メッセージ、スタックトレースを確認します。スタックトレースには、どのメソッドのどの行から問題が発生したかが示されます。

10-2. 変数・型・nullでつまずいたときの確認ポイント

型に関するエラーが発生した場合は、変数に代入しようとしている値の型を確認します。

int price = "3000";

このコードでは、stringintへ直接代入しているためエラーになります。文字列を数値へ変換する必要があります。

int price = int.Parse("3000");

また、Console.ReadLineなどの戻り値はnullになる可能性があります。必要に応じて、nullチェックや??演算子を使います。

string input = Console.ReadLine() ?? "";

参照型の変数がnullになる可能性を無視すると、実行時にNullReferenceExceptionが発生することがあります。

10-3. ループや条件分岐が思い通りに動かない原因

条件分岐が期待どおりに動かない場合は、条件の境界値を確認します。

例えば、60点以上を合格とする場合、次の条件では60点が不合格になります。

if (score > 60)

正しくは次のようにします。

if (score >= 60)

ループでは、開始値、継続条件、増減処理の3点を確認します。

for (int i = 0; i < array.Length; i++)

配列の最後のインデックスはLength - 1です。条件をi <= array.Lengthにすると、配列の範囲外へアクセスします。

処理の流れがわからない場合は、ループ内で変数の値を表示してみましょう。

Console.WriteLine($"i={i}, sum={sum}");

デバッガーのブレークポイントやステップ実行も有効です。

10-4. オブジェクト指向が理解できないときの学習手順

オブジェクト指向は、最初から継承や抽象クラスを理解しようとすると難しく感じやすい分野です。次の順序で学習します。

  1. 関連する変数をクラスへまとめる

  2. データをプロパティとして定義する

  3. データに関係する処理をメソッドにする

  4. コンストラクタで初期値を保証する

  5. private setで不正な変更を防ぐ

  6. 共通する性質を継承やインターフェースで表現する

例えば、商品名、価格、在庫数を別々の変数として扱うのではなく、Productクラスへまとめることから始めます。

public class Product{public string Name { get; }public decimal Price { get; }public int Stock { get; private set; }}

クラスを作る目的は、難しい構造を作ることではありません。関連するデータと処理をまとめ、誤った操作を防ぎ、変更しやすくすることです。

10-5. 解答を写すだけで終わらせない復習方法

解答例をそのまま入力して実行するだけでは、自力でコードを書く力が十分に身につきません。解答を確認した後は、次の復習を行います。

  • コードを見ずに最初から書き直す

  • 変数名や入力値を変更する

  • 条件を追加する

  • 別の方法で実装する

  • メソッドやクラスへ分割する

  • 不正な入力を与えて動作を確認する

FizzBuzzであれば、7の倍数で別の文字を表示する条件を追加できます。商品検索であれば、完全一致、部分一致、価格範囲検索へ発展させられます。

「解答を理解した」と「自力で再現できる」は別です。翌日や1週間後に、同じ問題を解き直して定着度を確認しましょう。

11. C#演習をさらに深める学習ステップ

11-1. コンソールアプリからWindowsアプリへ進む

コンソールアプリで基本文法、クラス、コレクションを理解したら、画面を持つアプリケーションへ進めます。

Windows向けの選択肢には、Windows Forms、WPF、WinUIなどがあります。最初は、次のような小規模アプリを作るとよいでしょう。

  • 電卓

  • ToDoリスト

  • メモ帳

  • 商品管理画面

  • 顧客検索画面

コンソールアプリでは文字入力だった処理を、テキストボックスやボタン操作へ置き換えます。入力チェックやクラス設計など、この記事で学んだ内容をそのまま活用できます。

11-2. ASP.NET CoreでWebアプリ開発に挑戦する

C#でWebアプリケーションを作る場合は、ASP.NET Coreを学習します。

最初の演習として、次の機能を持つアプリが適しています。

  • 商品一覧の表示

  • 商品詳細の表示

  • 商品の新規登録

  • 商品情報の編集

  • 商品の削除

  • 入力エラーの表示

コンソールアプリとの大きな違いは、HTTPリクエストを受け取り、HTMLやJSONで結果を返すことです。ただし、商品クラス、入力検証、検索、集計といった基本的な処理は共通しています。

11-3. データベース連携の演習に進む

実務アプリでは、商品や顧客をメモリ上のListだけで管理するのではなく、データベースへ保存します。

学習する項目は次のとおりです。

  • SQLの基本

  • テーブル設計

  • 主キーと外部キー

  • データの追加・検索・更新・削除

  • Entity Framework Core

  • トランザクション

  • 非同期処理

最初は、商品テーブルに対する登録、一覧、編集、削除を実装します。その後、顧客、注文、注文明細のように複数のテーブルを関連付けます。

11-4. GitHubでポートフォリオ化する方法

演習で作成したアプリは、GitHubへ登録すると学習記録やポートフォリオとして活用できます。

リポジトリには、少なくとも次の内容を含めます。

  • アプリケーションの概要

  • 実装した機能

  • 使用した技術

  • 実行方法

  • 工夫した点

  • 今後追加したい機能

  • 画面がある場合はスクリーンショット

100個の小さなコードをそのまま並べるより、複数の演習を組み合わせた完成度の高いアプリを2~3個作るほうが、設計力や実装力を示しやすくなります。

例えば、問題91~100を発展させ、データベース保存、ログイン、検索、ページングなどを追加すると、実務に近いポートフォリオになります。

11-5. C#初心者が実務レベルへ進むための学習順序

C#初心者が実務レベルを目指す場合は、次の順序で進めます。

  1. 変数、条件分岐、ループ

  2. 配列、List、Dictionary

  3. メソッドと例外処理

  4. クラスとオブジェクト指向

  5. LINQとファイル操作

  6. Gitによるバージョン管理

  7. SQLとデータベース

  8. ASP.NET Coreまたはデスクトップ開発

  9. テストコード

  10. 小規模アプリの完成

文法を完全に暗記してから次へ進む必要はありません。簡単なアプリを作り、不足している知識を調べながら補う学習方法が効果的です。

12. C#演習問題に関するよくある質問

12-1. C#初心者はどの演習問題から始めるべきか

プログラミングが初めての場合は、問題1から順番に進めましょう。特に、変数、条件分岐、繰り返し処理は、その後のすべての演習で使用します。

すでにJavaやPythonなどの経験がある場合は、問題1~20を復習として解き、問題41以降のコレクション、クラス、LINQを重点的に学ぶ方法もあります。

最初から難しい問題に挑戦するより、「少し考えれば解ける問題」を繰り返し解き、コードを書くことに慣れるのが重要です。

12-2. C#演習はどのくらいの期間続ければよいか

毎日30分から1時間学習する場合、基礎問題40問には2~4週間程度が目安です。その後、配列、クラス、LINQ、実務想定問題へ進みます。

ただし、必要な期間は学習経験や確保できる時間によって異なります。問題数や学習期間よりも、次の状態になっているかを確認しましょう。

  • 解答を見ずに基本的な処理を書ける

  • エラーを読んで修正できる

  • 処理をメソッドへ分割できる

  • データをクラスとして表現できる

  • 不正入力を考慮できる

  • 小規模なアプリを完成させられる

12-3. C#の解答を見ても理解できないときはどうするか

解答が理解できない場合は、コード全体を一度に理解しようとせず、1行ずつ変数の値を確認します。

例えばLINQの処理が難しい場合は、メソッドを分けて確認します。

var filtered = products.Where(product => product.Stock > 0);

var ordered = filtered.OrderBy(product => product.Price);

var result = ordered.ToList();

また、LINQをいったんforeachへ書き換えると、内部で行われている処理を理解しやすくなります。

知らないメソッドが登場した場合は、引数、戻り値、要素がない場合の動作を確認しましょう。

12-4. C#演習だけで実務スキルは身につくか

演習問題だけでも、文法、アルゴリズム、コレクション操作、クラス設計などの基礎は身につきます。ただし、実務では複数の技術を組み合わせる必要があります。

実務レベルを目指すには、演習に加えて次の経験が必要です。

  • 要件から必要な機能を整理する

  • 複数ファイルにコードを分割する

  • データベースを利用する

  • Gitで変更履歴を管理する

  • テストを書く

  • 他人が読めるコードを書く

  • 不具合を調査して修正する

  • アプリを最後まで完成させる

100問を解き終えたら、商品管理、家計簿、予約管理など、自分でテーマを決めたアプリへ進みましょう。

12-5. JavaやPython経験者がC#演習で注意すべき点

Java経験者はC#の構文を理解しやすい一方、プロパティ、LINQ、デリゲート、ラムダ式、非同期処理など、C#特有の機能を意識して学ぶ必要があります。

Python経験者は、C#では変数や戻り値の型を明確に扱う点に注意します。また、インデントだけでなく波かっこでブロックを表し、コンパイル時に多くの型エラーを検出できる点も異なります。

どちらの経験者も、以前の言語の書き方をそのまま移すのではなく、次のC#らしい機能を練習すると効果的です。

  • プロパティ

  • ジェネリックコレクション

  • LINQ

  • null許容参照型

  • パターンマッチング

  • レコード

  • asyncawait

  • usingによるリソース管理

まとめ

C#を身につけるには、文法を読むだけでなく、演習問題を通じて自分でコードを書くことが欠かせません。

最初は変数、条件分岐、繰り返し処理から始め、配列、List、Dictionary、メソッド、クラスへ進みます。その後、例外処理、ファイル操作、日時処理、LINQを学ぶことで、業務データを扱うための基礎が身につきます。

本記事のC#演習問題100選は、次の順序で活用してください。

  1. 問題を読んで入出力と処理手順を整理する

  2. 解答を見ずにコードを書く

  3. 実行してエラーを修正する

  4. 解答例と比較する

  5. コードを見ずに書き直す

  6. 条件や機能を追加して発展させる

問題100まで終えたら、商品管理アプリをファイル保存やデータベース対応へ発展させてみましょう。演習で覚えた知識を1つのアプリに組み合わせることが、C#初心者から実務レベルへ進むための重要なステップです。