初心者でも分かる C# ToString() オーバーライド入門

この記事のゴール

  • 「ToString() ってそもそも何?」が分かる
  • 自分のクラスで ToString() をオーバーライドできる
  • デバッグやログ出力がグッと楽になる

1. ToString() とは?

  • すべてのクラスの祖先である object が持つメソッド
  • 既定では 型名 を返すだけ
var p = new Point(3, 5);
Console.WriteLine(p.ToString());   // → "Point"
  • “オブジェクトを文字列に変換する共通インターフェース” と覚えよう

2. どうしてオーバーライドするの?

シーン便利になる理由
デバッグ変数をウォッチした瞬間に中身が見える
ログ出力解析しやすい形で記録できる
画面表示ドロップダウンや一覧に “人が読めるラベル” を出せる

3. 基本ステップ(最短 3 行)

public override string ToString()
{
    return $"{Title} ({Author})";
}
  1. override を付ける
  2. 戻り値は string 固定
  3. return で“見せたい形”の文字列を返す

4. 具体例でマスターしよう

4-1. いちばんシンプルな例 ― Book クラス

class Book
{
    public string Title  { get; set; }
    public string Author { get; set; }

    public override string ToString()
    {
        return $"{Title} / {Author}";
    }
}
var book = new Book { Title = "人間失格", Author = "太宰治" };
Console.WriteLine(book);  // → 人間失格 / 太宰治

4-2. 少しだけ発展 ― 年齢や金額を計算

class Employee
{
    public string Name      { get; set; }
    public DateTime Birthday { get; set; }
    public decimal Salary   { get; set; }

    public override string ToString()
    {
        int age = (int)((DateTime.Today - Birthday).TotalDays / 365.25);
        return $"{Name,-8} | 年齢:{age,2} | 給与:{Salary:N0}円";
    }
}

以下に、①単体で使うパターン と ②リストに入れて活用するパターン の2種類を示します。

すべてコピー&ペーストでそのままビルド/実行できます。

1. 単体で使う

using System;

class Program
{
    static void Main()
    {
        // 1-1. オブジェクト初期化子でプロパティを一気に設定
        var alice = new Employee
        {
            Name      = "Alice",
            Birthday  = new DateTime(1995, 4, 12),
            Salary    = 4_200_000m
        };

        // 1-2. Console.WriteLine へ直接渡すだけで ToString() が呼び出される
        Console.WriteLine(alice);
        // → Alice    | 年齢:30 | 給与:4,200,000円
    }
}

class Employee
{
    public string  Name     { get; set; }
    public DateTime Birthday { get; set; }
    public decimal Salary    { get; set; }

    public override string ToString()
    {
        int age = (int)((DateTime.Today - Birthday).TotalDays / 365.25);
        return $"{Name,-8} | 年齢:{age,2} | 給与:{Salary:N0}円";
    }
}

ポイント

  • Console.WriteLine(オブジェクト) で自動的に ToString() が呼ばれる
  • Name,-8 は「全角半角混在でも 8 文字幅に左寄せ」で揃えるフォーマット指定

2. リストに入れて一覧表示する

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

class Program
{
    static void Main()
    {
        var employees = new List<Employee>
        {
            new Employee { Name = "Alice",  Birthday = new DateTime(1995, 4, 12), Salary = 4_200_000m },
            new Employee { Name = "Bob",    Birthday = new DateTime(1988, 9,  5), Salary = 5_800_000m },
            new Employee { Name = "Charlie",Birthday = new DateTime(2000, 1, 23), Salary = 3_600_000m },
        };

        // 2-1. 給与の高い順に並べ替え
        var sorted = employees.OrderByDescending(e => e.Salary);

        // 2-2. string.Join で一括表示(改行区切り)
        Console.WriteLine(string.Join(Environment.NewLine, sorted));
        /*
          Bob      | 年齢:36 | 給与:5,800,000円
          Alice    | 年齢:30 | 給与:4,200,000円
          Charlie  | 年齢:25 | 給与:3,600,000円
        */
    }
}

class Employee
{
    public string  Name     { get; set; }
    public DateTime Birthday { get; set; }
    public decimal Salary    { get; set; }

    public override string ToString()
    {
        int age = (int)((DateTime.Today - Birthday).TotalDays / 365.25);
        return $"{Name,-8} | 年齢:{age,2} | 給与:{Salary:N0}円";
    }
}

ポイント

  1. OrderByDescending で並び順を変更しても ToString() の中身は触らない
  2. string.Join(“\n", list) でループ無しにまとめて表示できる
  3. Employee クラス側の修正が不要なので、UI やログ出力をあとから変えたいときは ToString() だけ直せば良い

3. 初心者向け練習課題

課題ヒント
A. Salary の中央値(メディアン)を求めて表示sorted.Skip(count/2).First()
B. 年齢が 30 歳未満の社員だけを取り出し、JSON 風 の 1 行に整形して表示Where と $"{{ \"Name\":\"{e.Name}\", \"Age\":{age} }}"
C. Employee に部署 (Department) を追加し、ToString() にも含める既存の戻り値に `$”

コツ: どの課題も アプリ本体 は LINQ やフォーマットの操作だけで済みます。Employee 側はプロパティを増やす&ToString() を変更するだけで対応できる設計になっているかを確認してみましょう。


5. 失敗しないための 3 か条

  1. 重い処理は入れない
    • デバッグウィンドウを開くたびに時間がかかる
  2. 機密情報を書かない
    • パスワード・トークンは絶対に表示しない
  3. 例外を投げない
    • ToString() 中の例外は意外と落とし穴。エラー時は “InvalidState" のような文字列を返すほうが安全

6. 練習してみよう ✍️

  1. Student クラスを作成
    • Name と Score(0-100)を持つ
    • ToString() で「Name: Alice, Rank: S」の形で表示
      • ランク:S(90-), A(80-89), B(70-79), C(60-69), D(-59)
  2. Employee リストを一括表示
    • List<Employee> を生成
    • Console.WriteLine(string.Join(“\n", employees)); で全員の情報が給与の高い順に表示されるよう ToString() を実装

サンプル回答 — Studentと Employeeの両課題を 1 つのコンソールアプリにまとめた例

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

class Program
{
    static void Main()
    {
        // ─────────────────────────────────────
        // 1. Student クラスのテスト
        // ─────────────────────────────────────
        var s1 = new Student { Name = "Alice",  Score = 95 };
        var s2 = new Student { Name = "Bob",    Score = 82 };
        var s3 = new Student { Name = "Carol",  Score = 67 };
        Console.WriteLine("=== Student ===");
        Console.WriteLine(s1);   // → Name: Alice,  Rank: S
        Console.WriteLine(s2);   // → Name: Bob,    Rank: A
        Console.WriteLine(s3);   // → Name: Carol,  Rank: C

        // ─────────────────────────────────────
        // 2. Employee リストを一括表示
        // ─────────────────────────────────────
        var employees = new List<Employee>
        {
            new Employee { Name = "Alice",   Birthday = new DateTime(1995, 4, 12), Salary = 4_200_000m },
            new Employee { Name = "Bob",     Birthday = new DateTime(1988, 9,  5), Salary = 5_800_000m },
            new Employee { Name = "Charlie", Birthday = new DateTime(2000, 1, 23), Salary = 3_600_000m },
        };

        var sorted = employees.OrderByDescending(e => e.Salary);
        Console.WriteLine("\n=== Employee (給与の高い順) ===");
        Console.WriteLine(string.Join(Environment.NewLine, sorted));
    }
}

// ─────────────────────────────────────────────────────────
// Student クラス
// ─────────────────────────────────────────────────────────
class Student
{
    public string Name  { get; set; }
    public int    Score { get; set; }   // 0–100

    public override string ToString()
    {
        string rank = Score switch
        {
            >= 90           => "S",
            >= 80 and < 90  => "A",
            >= 70 and < 80  => "B",
            >= 60 and < 70  => "C",
            _               => "D"
        };
        // -10 文字幅で左寄せし、見映えをそろえる
        return $"Name: {Name,-10} Rank: {rank}";
    }
}

// ─────────────────────────────────────────────────────────
// Employee クラス
// ─────────────────────────────────────────────────────────
class Employee
{
    public string  Name     { get; set; }
    public DateTime Birthday { get; set; }
    public decimal Salary    { get; set; }

    public override string ToString()
    {
        int age = (int)((DateTime.Today - Birthday).TotalDays / 365.25);
        return $"{Name,-8} | 年齢:{age,2} | 給与:{Salary:N0}円";
    }
}

動作例

=== Student ===
Name: Alice      Rank: S
Name: Bob        Rank: A
Name: Carol      Rank: C

=== Employee (給与の高い順) ===
Bob      | 年齢:36 | 給与:5,800,000円
Alice    | 年齢:30 | 給与:4,200,000円
Charlie  | 年齢:25 | 給与:3,600,000円

上記を丸ごとコピーして実行すれば、

  • Student.ToString() ではランクが正しく付与されること、
  • 給与の降順 で Employee がリスト表示されることを確認できます。

7. まとめ

  • ToString() は オブジェクトの自己紹介カード
  • オーバーライドで 見やすさ と 開発効率 が向上
  • コツは「簡潔・安全・高速
  • まずは自分のクラスに 3 行書いて、デバッグ体験を変えてみよう!
訪問数 7 回, 今日の訪問数 1回