10日目のゴールとテーマ
10日目のテーマは「クラスとオブジェクトで“自分の型”を作る」です。
ここまでは、int や string、DateTime のような「既に用意されている型」を使ってきました。
今日は一歩進んで、
自分で「診断結果」という型を作る
その型の“ひな型”をクラスとして定義する
実際のデータを“オブジェクト”として扱う
という、C# の本丸に入っていきます。
完璧に理解しなくて大丈夫です。
「クラス=設計図」「オブジェクト=実物」という感覚が持てれば、今日は成功です。
クラスとオブジェクトをイメージでつかむ
「設計図」と「実物」の関係
まずは、コードから離れてイメージで考えます。
家を建てるとき、いきなり現場で「こんな感じで!」とはやりません。
必ず「設計図」を描きますよね。
クラスは、この「設計図」にあたります。
「この型のデータは、こういう項目を持っている」という定義です。
一方で、実際に建った家は「実物」です。
クラスから作られた具体的なデータを、オブジェクト(インスタンス)と呼びます。
C# では、
クラス → 型の設計図
オブジェクト → その型の実体(1 件分のデータ)
と考えてください。
「診断結果」をクラスにしてみるイメージ
9日目までのログ 1 行には、こんな情報がありました。
日時
はいの数 / 質問数
タイプコード(ACTIVE / BALANCE / INDOOR)
これを「診断結果」という 1 つの“もの”として扱いたい。
そのための設計図が、クラスです。
診断結果クラスを定義する
最小限の Result クラスを書いてみる
まずは、超シンプルなクラスから始めます。
class Result
{
public DateTime Timestamp;
public int YesCount;
public int Total;
public string TypeCode;
}
C#ここでやっていることを分解します。
class Result
Result という名前のクラス(型)を定義している。
中の 4 行
このクラスが持つ「項目(フィールド)」を定義している。
それぞれの型と名前を決めている。
つまり、「Result 型のデータは、
日時(Timestamp)、はいの数(YesCount)、質問数(Total)、タイプコード(TypeCode)
を持っている」という宣言です。
public の意味
public は「外からアクセスできる」という意味です。
今日は細かいアクセス修飾子の話には踏み込みませんが、
とりあえず「他の場所から result.YesCount のように触れるようにしている」と思ってください。
クラスからオブジェクトを作る
new で「実物」を作る
クラスは設計図なので、それだけでは何も起きません。
実際のデータ(オブジェクト)を作るには、new を使います。
Result r = new Result();
r.Timestamp = DateTime.Now;
r.YesCount = 3;
r.Total = 5;
r.TypeCode = "BALANCE";
C#ここでの流れはこうです。
new Result() で「Result 型の空の箱」を 1 つ作る
その箱に、1 つずつ値を入れていく
この r が「1 回分の診断結果」という“実物”です。
配列やリストでまとめて扱うイメージ
Result が 1 つ作れたら、複数をまとめて扱うこともできます。
Result[] results = new Result[3];
results[0] = new Result();
results[0].YesCount = 3;
// …というように入れていく
C#今日は配列にこだわらなくてもいいですが、
「int[] の代わりに Result[] を持てる」という感覚だけ持っておいてください。
ログ1行を Result オブジェクトに変換する
9日目の「行を分解する処理」をクラスに寄せる
9日目では、ログの 1 行をこう分解していました。
string line = "2026-03-02 19:30,3/5,BALANCE";
string[] parts = line.Split(',');
string timestamp = parts[0];
string scorePart = parts[1];
string typeCode = parts[2];
C#これを「Result を作る処理」としてまとめてみます。
static Result ParseLogLine(string line)
{
string[] parts = line.Split(',');
if (parts.Length != 3)
{
return null;
}
string timestampText = parts[0];
string scorePart = parts[1];
string typeCode = parts[2];
string[] scoreParts = scorePart.Split('/');
if (scoreParts.Length != 2)
{
return null;
}
int yesCount = int.Parse(scoreParts[0]);
int total = int.Parse(scoreParts[1]);
DateTime timestamp = DateTime.Parse(timestampText);
Result r = new Result();
r.Timestamp = timestamp;
r.YesCount = yesCount;
r.Total = total;
r.TypeCode = typeCode;
return r;
}
C#ここでの重要ポイントを深掘りします。
行をカンマで分割して、3 つの部分に分ける
スコア部分(”3/5″)をさらに / で分割して、数値に変換する
日時文字列を DateTime.Parse で DateTime 型に変換する
最後に Result オブジェクトを作って、そこに全部詰める
これで、「文字列としての 1 行」から「Result というオブジェクト」に変換できました。
Result を使って履歴を表示する
オブジェクトを使うとコードが読みやすくなる
9日目の ShowLogHistory は、文字列配列と Split を直接扱っていました。
これを Result を使う形に書き換えてみます。
static void ShowLogHistory()
{
string fileName = "log.txt";
if (!File.Exists(fileName))
{
Console.WriteLine("まだログはありません。");
Console.WriteLine();
return;
}
string[] lines = File.ReadAllLines(fileName);
Console.WriteLine("=== ログ履歴 ===");
for (int i = 0; i < lines.Length; i++)
{
Result r = ParseLogLine(lines[i]);
if (r == null)
{
continue;
}
string typeLabel = ConvertTypeCodeToLabel(r.TypeCode);
Console.WriteLine(
r.Timestamp.ToString("yyyy-MM-dd HH:mm")
+ " "
+ r.YesCount + "/" + r.Total
+ " "
+ typeLabel
);
}
Console.WriteLine("=== ここまで ===");
Console.WriteLine();
}
C#ここで注目してほしいのは、
r.Timestampr.YesCountr.Totalr.TypeCode
のように、「診断結果」というまとまりを 1 つの変数 r で扱えていることです。
文字列配列をゴリゴリ触るよりも、
「Result という“意味のある型”」を通して扱った方が、
コードの意図が読み取りやすくなります。
クラスに「振る舞い」を持たせる一歩手前
Result に「ラベルを返すメソッド」を持たせるイメージ
今は、タイプコードを日本語に変換するメソッドが
Program クラス側にあります。
static string ConvertTypeCodeToLabel(string typeCode)
{
// switch で ACTIVE / BALANCE / INDOOR を日本語に
}
C#これを、Result クラスの中に入れることもできます。
イメージとしてはこうです。
class Result
{
public DateTime Timestamp;
public int YesCount;
public int Total;
public string TypeCode;
public string GetTypeLabel()
{
switch (TypeCode)
{
case "ACTIVE":
return "超アクティブタイプ";
case "BALANCE":
return "バランスタイプ";
case "INDOOR":
return "インドアタイプ";
default:
return "不明なタイプ";
}
}
}
C#こうしておくと、履歴表示側はこう書けます。
Console.WriteLine(
r.Timestamp.ToString("yyyy-MM-dd HH:mm")
+ " "
+ r.YesCount + "/" + r.Total
+ " "
+ r.GetTypeLabel()
);
C#「Result 自身が、自分のタイプラベルを知っている」
という形になっていて、これがまさに「オブジェクトに振る舞いを持たせる」考え方です。
今日はここを“チラ見せ”くらいで十分です。
「クラスはデータだけでなく、関連する処理も一緒に持てる」という感覚だけ持っておいてください。
10日目のまとめ
今日のポイントを整理します。
クラス
自分で作る「型の設計図」。どんな項目(フィールド)を持つかを定義する。
オブジェクト(インスタンス)
クラスから new で作られる「実物」。1 件分のデータ。
Result クラス
診断結果を 1 つの“もの”として扱うための型。
日時・はいの数・質問数・タイプコードをまとめて持てる。
ParseLogLine
ログ 1 行(文字列)から Result オブジェクトを作る処理。
「文字列の世界」から「型の世界」に変換している。
型に意味を持たせるstring の配列でバラバラに扱うより、Result という名前の型でまとめた方が、コードの意図が読みやすくなる。
ここまで来ると、「C# の文法を知っている」から
「C# らしい書き方に入り始めている」段階に入っています。
次回(11日目)への予告
11日目は、この Result クラスの考え方を広げて、
複数の Result をまとめて扱う「コレクション」
LINQ の入り口(集計やフィルタを簡潔に書く)
「最近 5 件だけ表示する」「タイプごとの件数を出す」
といった、「データをオブジェクトとして扱う」世界に進んでいきます。
