C# | 2週間で身につくアプリを作りながら学ぶC#の基本 - 10日目

C# C#
スポンサーリンク

10日目のゴールとテーマ

10日目のテーマは「クラスとオブジェクトで“自分の型”を作る」です。
ここまでは、intstringDateTime のような「既に用意されている型」を使ってきました。

今日は一歩進んで、

自分で「診断結果」という型を作る
その型の“ひな型”をクラスとして定義する
実際のデータを“オブジェクト”として扱う

という、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.Timestamp
r.YesCount
r.Total
r.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 件だけ表示する」「タイプごとの件数を出す」

といった、「データをオブジェクトとして扱う」世界に進んでいきます。

タイトルとURLをコピーしました