基礎から学ぶC#入門 90日コース | アプリを作りながら学ぶ - Day 74:Read

Web APP 90日で身につけるC#
スポンサーリンク
スポンサーリンク

Day 74 のゴールと全体像

Day 74 では、タスク管理アプリの「R」――Read(読み取り)機能をしっかり形にしていきます。 昨日までで「タスクを追加する(Create)」ところまではできましたので、 今日はそのタスクたちを 一覧として、わかりやすく表示する機能を作っていきます。

タスク管理アプリにとって、一覧画面はまさに「顔」です。 ここが見やすいかどうかで、アプリの印象がガラッと変わります。 ですので、単に「表示できればOK」ではなく、 読みやすさ・情報の整理・ちょっとした気遣いまで意識して設計していきます。

タスク一覧機能の役割を整理する

一覧機能は何をしてくれるのか

タスク一覧機能の役割は、ざっくり言うと次の3つです。

  • 登録されているタスクをすべて取り出す
  • 人間にとって読みやすい形に整形する
  • 「何もないとき」はそれも分かりやすく伝える

プログラム的には「リストをループして表示するだけ」に見えますが、 実際には、

  • 完了状態をどう表現するか
  • 優先度をどう見せるか
  • 期限がないタスクをどう扱うか

といった細かい設計が、使い心地に大きく影響してきます。

前提となる TaskItem と TaskRepository のおさらい

タスクの形:TaskItem

まずは、タスクのデータ構造をもう一度確認しておきます。

// タスクを表すクラス
class TaskItem
{
    public int Id { get; set; }                 // 一意なID
    public string Title { get; set; }           // タスク名
    public string Description { get; set; }     // 詳細・メモ
    public int Priority { get; set; }           // 優先度(1: 高, 2: 中, 3: 低)
    public DateTime? DueDate { get; set; }      // 期限(任意)
    public bool IsCompleted { get; set; }       // 完了フラグ
    public DateTime CreatedAt { get; set; }     // 作成日時
}
C#

タスク一覧を管理するクラス:TaskRepository

タスクを追加したり、一覧を取得したりする役割を持つクラスです。

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

// タスク一覧を管理するクラス
class TaskRepository
{
    private readonly List<TaskItem> _tasks = new List<TaskItem>();
    private int _nextId = 1;

    // タスク追加
    public TaskItem Add(string title, string description, int priority, DateTime? dueDate)
    {
        var task = new TaskItem
        {
            Id = _nextId++,
            Title = title,
            Description = description,
            Priority = priority,
            DueDate = dueDate,
            IsCompleted = false,
            CreatedAt = DateTime.Now
        };

        _tasks.Add(task);
        return task;
    }

    // 全タスク取得
    public IEnumerable<TaskItem> GetAll()
    {
        return _tasks;
    }
}
C#

Day 74 では、この GetAll() を使って一覧表示を作っていきます。

一覧表示の基本設計を考える

どんな情報を表示したいか

一覧画面に出したい情報を整理してみます。

  • ID:編集や削除のときに指定するための識別子
  • 完了状態:終わっているかどうかがひと目で分かるように
  • 優先度:どれから手をつけるべきかの目安
  • 期限:締め切りが近いものを意識するため
  • タイトル:タスクの内容をざっくり把握するため

これらを、1行または数行で読みやすく表示するのが目標です。

空のときの振る舞い

タスクが1件も登録されていないときに、 何も表示されないと「壊れているのかな?」と不安になります。

ですので、

  • タスクが0件なら「タスクが登録されていません。」と表示する

という振る舞いを、あらかじめ決めておきます。

タスク一覧表示の基本コード

シンプルな一覧表示メソッド

まずは、基本形となる一覧表示メソッドを書いてみます。

using System;
using System.Linq;

void ShowTasks()
{
    Console.WriteLine("=== タスク一覧 ===");

    // リポジトリから全タスクを取得
    var tasks = repository.GetAll();

    // タスクが1件もない場合
    if (!tasks.Any())
    {
        Console.WriteLine("タスクが登録されていません。");
        return;
    }

    // タスクがある場合、1件ずつ表示
    foreach (var t in tasks)
    {
        // 完了状態を文字に変換
        string status = t.IsCompleted ? "[完了]" : "[未完了]";

        // 優先度を文字に変換
        string priorityText = t.Priority switch
        {
            1 => "高",
            2 => "中",
            3 => "低",
            _ => "不明"
        };

        // 期限を文字に変換(期限なしの場合の扱いも含める)
        string dueText = t.DueDate.HasValue
            ? t.DueDate.Value.ToString("yyyy-MM-dd")
            : "期限なし";

        // 1行で表示する基本形
        Console.WriteLine(
            $"ID: {t.Id} {status} 優先度: {priorityText} 期限: {dueText} タイトル: {t.Title}"
        );
    }
}
C#

重要ポイントの深掘り

  • tasks.Any() のチェック Any() は「1件でもあるか?」を調べるメソッドです。 これで「空かどうか」を簡潔に判定できます。
  • 完了状態の表現 IsCompletedbool ですが、そのまま True/False と表示しても分かりづらいので、 [完了] / [未完了] に変換して、人間にとって読みやすくしています。
  • 優先度の表現 数値(1,2,3)を「高・中・低」に変換することで、 一覧を見たときに直感的に理解できるようになります。
  • 期限の表現 DateTime? は「null を許す型」なので、 HasValue で「期限があるかどうか」を判定し、 ない場合は「期限なし」と表示しています。

一覧表示を少し“見やすく”する工夫

カード風に表示してみる

1行に詰め込むのも悪くはないのですが、 タスクが増えてくると、少し読みづらく感じることもあります。

そこで、1件のタスクを「カード」のように複数行で表示してみます。

void ShowTasks()
{
    Console.WriteLine("=== タスク一覧 ===");

    var tasks = repository.GetAll();

    if (!tasks.Any())
    {
        Console.WriteLine("タスクが登録されていません。");
        return;
    }

    foreach (var t in tasks)
    {
        string status = t.IsCompleted ? "[完了]" : "[未完了]";
        string priorityText = t.Priority switch
        {
            1 => "高",
            2 => "中",
            3 => "低",
            _ => "不明"
        };
        string dueText = t.DueDate.HasValue
            ? t.DueDate.Value.ToString("yyyy-MM-dd")
            : "期限なし";

        Console.WriteLine($"ID: {t.Id}");
        Console.WriteLine($"  状態   : {status}");
        Console.WriteLine($"  優先度 : {priorityText}");
        Console.WriteLine($"  期限   : {dueText}");
        Console.WriteLine($"  タイトル: {t.Title}");
        Console.WriteLine(); // タスク同士の間に空行を入れて見やすくする
    }
}
C#

こうすると、

  • 1件1件が「まとまり」として目に入る
  • 状態・優先度・期限・タイトルが整理されて見える

というメリットがあります。

メニューから一覧機能を呼び出す

コンソールメニューとの連携

Day 73 で作ったメニューに、 「タスク一覧」を組み込んでいきます。

void Run()
{
    while (true)
    {
        Console.WriteLine("=== タスク管理アプリ ===");
        Console.WriteLine("1: タスク追加");
        Console.WriteLine("2: タスク一覧");
        Console.WriteLine("0: 終了");
        Console.Write("選択してください: ");

        string input = Console.ReadLine();

        switch (input)
        {
            case "1":
                CreateTask();   // Day 73 で作った追加機能
                break;
            case "2":
                ShowTasks();    // 今日作った一覧機能
                break;
            case "0":
                Console.WriteLine("終了します。");
                return;
            default:
                Console.WriteLine("不正な入力です。");
                break;
        }

        Console.WriteLine(); // 画面の区切り用に空行を入れる
    }
}
C#

これで、

  • 「1」でタスク追加
  • 「2」でタスク一覧
  • 「0」で終了

という、基本的な C(Create)と R(Read) の流れが完成します。

Day 74 用ミニテンプレート(まとめて貼れるサンプル)

Day 73 のコードに、今日の一覧機能を組み込んだ形のサンプルです。

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

// タスクを表すクラス
class TaskItem
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public int Priority { get; set; }
    public DateTime? DueDate { get; set; }
    public bool IsCompleted { get; set; }
    public DateTime CreatedAt { get; set; }
}

// タスク一覧を管理するクラス
class TaskRepository
{
    private readonly List<TaskItem> _tasks = new List<TaskItem>();
    private int _nextId = 1;

    public TaskItem Add(string title, string description, int priority, DateTime? dueDate)
    {
        var task = new TaskItem
        {
            Id = _nextId++,
            Title = title,
            Description = description,
            Priority = priority,
            DueDate = dueDate,
            IsCompleted = false,
            CreatedAt = DateTime.Now
        };

        _tasks.Add(task);
        return task;
    }

    public IEnumerable<TaskItem> GetAll()
    {
        return _tasks;
    }
}

class Program
{
    static TaskRepository repository = new TaskRepository();

    static void Main()
    {
        Run();
    }

    static void Run()
    {
        while (true)
        {
            Console.WriteLine("=== タスク管理アプリ ===");
            Console.WriteLine("1: タスク追加");
            Console.WriteLine("2: タスク一覧");
            Console.WriteLine("0: 終了");
            Console.Write("選択してください: ");

            string input = Console.ReadLine();

            switch (input)
            {
                case "1":
                    CreateTask();
                    break;
                case "2":
                    ShowTasks();
                    break;
                case "0":
                    Console.WriteLine("終了します。");
                    return;
                default:
                    Console.WriteLine("不正な入力です。");
                    break;
            }

            Console.WriteLine();
        }
    }

    static void CreateTask()
    {
        Console.WriteLine("=== タスク追加 ===");

        string title = ReadTitle();
        string description = ReadDescription();
        int priority = ReadPriority();
        DateTime? dueDate = ReadDueDate();

        TaskItem task = repository.Add(title, description, priority, dueDate);

        Console.WriteLine($"タスクを追加しました。ID: {task.Id}");
    }

    static string ReadTitle()
    {
        while (true)
        {
            Console.Write("タスク名を入力してください: ");
            string title = Console.ReadLine();

            if (!string.IsNullOrWhiteSpace(title))
            {
                return title;
            }

            Console.WriteLine("タスク名は必須です。空では登録できません。");
        }
    }

    static string ReadDescription()
    {
        Console.Write("詳細(メモ)を入力してください(空でも構いません): ");
        string description = Console.ReadLine();
        return description ?? string.Empty;
    }

    static int ReadPriority()
    {
        while (true)
        {
            Console.Write("優先度を入力してください (1: 高, 2: 中, 3: 低): ");
            string text = Console.ReadLine();

            if (int.TryParse(text, out int value))
            {
                if (value == 1 || value == 2 || value == 3)
                {
                    return value;
                }
            }

            Console.WriteLine("優先度は 1, 2, 3 のいずれかで入力してください。");
        }
    }

    static DateTime? ReadDueDate()
    {
        while (true)
        {
            Console.Write("期限を入力してください (yyyy-MM-dd、未入力なら期限なし): ");
            string text = Console.ReadLine();

            if (string.IsNullOrWhiteSpace(text))
            {
                return null;
            }

            if (DateTime.TryParse(text, out DateTime date))
            {
                return date;
            }

            Console.WriteLine("日付の形式が正しくありません。例: 2026-09-10 のように入力してください。");
        }
    }

    static void ShowTasks()
    {
        Console.WriteLine("=== タスク一覧 ===");

        var tasks = repository.GetAll();

        if (!tasks.Any())
        {
            Console.WriteLine("タスクが登録されていません。");
            return;
        }

        foreach (var t in tasks)
        {
            string status = t.IsCompleted ? "[完了]" : "[未完了]";
            string priorityText = t.Priority switch
            {
                1 => "高",
                2 => "中",
                3 => "低",
                _ => "不明"
            };
            string dueText = t.DueDate.HasValue
                ? t.DueDate.Value.ToString("yyyy-MM-dd")
                : "期限なし";

            Console.WriteLine($"ID: {t.Id}");
            Console.WriteLine($"  状態   : {status}");
            Console.WriteLine($"  優先度 : {priorityText}");
            Console.WriteLine($"  期限   : {dueText}");
            Console.WriteLine($"  タイトル: {t.Title}");
            Console.WriteLine();
        }
    }
}
C#

Day 74 のまとめ

Day 74 では、タスク管理アプリの Read(一覧表示)機能を丁寧に作り上げました。

  • タスク一覧を取得する GetAll() を使い
  • 空の場合のメッセージを用意し
  • 完了状態・優先度・期限を、人間にとって読みやすい形に整形し
  • カード風の表示で、タスク1件1件が見やすくなるように工夫しました。

これで、

「タスクを追加する」 → 「一覧で確認する」

という、アプリの基本的な流れが完成しました。

次のステップでは、 この一覧表示を土台にして、

  • 特定のタスクを探す検索機能
  • 編集や削除の対象を選ぶための表示

など、さらに一歩踏み込んだ「Read」の世界に進んでいきます。

タスクが増えていくほど、 一覧表示のありがたみがじわじわと効いてきますので、 今日作ったこの機能を、ぜひ自分の手で動かしてみて、 「見えるって、やっぱり気持ちいいな」と感じてもらえたらうれしいです。

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