bucket-sort logo bucket-sort

プログラミングとインフラエンジニアリングの覚え書き

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] System.Object クラスを整理する — すべてのクラスの基底クラスと提供されるメソッド

[C#] System.Object クラスを整理する — すべてのクラスの基底クラスと提供されるメソッド

May 1, 2026 C# , .NET bucket-sort

C# のすべてのクラスは、明示的に継承元を指定しない場合、暗黙的に System.Object クラスから派生します。System.Object は .NET の型階層の頂点 に位置するクラスで、「基底クラス(Base Class)」あるいは「ルートクラス」と呼ばれます。「スーパー親クラス」という俗称で呼ばれることもあります。

// この 2 つは等価
public class MyClass { }
public class MyClass : System.Object { }

object キーワードは System.Object の C# エイリアスです(string が System.String のエイリアスであるのと同様です)。

System.Object の役割

System.Object が提供する主な役割は次の 3 つです。

  1. 共通インターフェースの提供 — Equals・GetHashCode・ToString などのメソッドをすべての型に保証します
  2. ポリモーフィズムの基盤 — object 型の変数にあらゆる型のインスタンスを代入できます(ボックス化)
  3. リフレクションの起点 — GetType() でランタイム型情報を取得できます

メソッド一覧

メソッド 種類 説明
ToString() virtual オブジェクトの文字列表現を返す
Equals(object?) virtual 等値比較を行う
GetHashCode() virtual ハッシュコードを返す
GetType() 非 virtual ランタイムの型情報を返す
MemberwiseClone() protected シャローコピーを作成する
ReferenceEquals(object?, object?) static 参照の同一性を比較する
Finalize() protected virtual ガベージコレクション前の処理(C# では ~デストラクタ 構文)

ToString() — 文字列表現

デフォルトでは型の完全修飾名(名前空間.クラス名)を返します。意味のある文字列を返すようにオーバーライドするのが一般的です。

var p = new Person { Name = "Alice", Age = 30 };
Console.WriteLine(p.ToString()); // → "名前空間.Person"(デフォルト)

オーバーライドの例

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

    public override string ToString()
        => $"Person {{ Name = {Name}, Age = {Age} }}";
}

var p = new Person { Name = "Alice", Age = 30 };
Console.WriteLine(p); // → Person { Name = Alice, Age = 30 }

Console.WriteLine や文字列補間 $"{obj}" は内部で ToString() を呼び出すため、オーバーライドするとデバッグや出力で非常に役立ちます。

Equals() — 等値比較

デフォルトの Equals は参照の同一性(同じインスタンスかどうか)を比較します。値の等値比較を行いたい場合はオーバーライドが必要です。

var a = new Person { Name = "Alice", Age = 30 };
var b = new Person { Name = "Alice", Age = 30 };

Console.WriteLine(a.Equals(b)); // False(別のインスタンス)
Console.WriteLine(a == b);      // False(同上)

オーバーライドの例

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

    public override bool Equals(object? obj)
    {
        if (obj is not Person other) return false;
        return Name == other.Name && Age == other.Age;
    }

    public override int GetHashCode()
        => HashCode.Combine(Name, Age);
}

var a = new Person { Name = "Alice", Age = 30 };
var b = new Person { Name = "Alice", Age = 30 };

Console.WriteLine(a.Equals(b)); // True

Equals オーバーライドの注意点

Equals をオーバーライドする場合は 必ず GetHashCode も同時にオーバーライドしてください。これは、.NET の規約「等値なオブジェクトは同じハッシュコードを持たなければならない」を守るためです。守らないと Dictionary や HashSet が正しく動作しません。

// NG: Equals をオーバーライドしたが GetHashCode はデフォルトのまま
var dict = new Dictionary<Person, string>();
dict[new Person { Name = "Alice", Age = 30 }] = "エンジニア";

// 別のインスタンスだがハッシュコードが異なるためキーが見つからない
var key = new Person { Name = "Alice", Age = 30 };
Console.WriteLine(dict.ContainsKey(key)); // False(意図しない結果)

GetHashCode() — ハッシュコード

Dictionary<TKey, TValue> や HashSet<T> などのハッシュベースのコレクションが内部でキーを管理するために使用します。

実装の指針

  • 同じ値を持つオブジェクトは同じハッシュコードを返す(必須)
  • 異なる値はできるだけ異なるハッシュコードを返す(衝突を減らすため)
  • HashCode.Combine() を使うと簡潔かつ品質の高いハッシュ値を生成できます
public override int GetHashCode()
    => HashCode.Combine(Name, Age);  // .NET Core 2.1 以降推奨

GetType() — 型情報の取得

オブジェクトのランタイム型を表す Type インスタンスを返します。オーバーライドできません。

object obj = "Hello";
Type t = obj.GetType();

Console.WriteLine(t.Name);          // String
Console.WriteLine(t.FullName);      // System.String
Console.WriteLine(t.IsValueType);   // False

型チェックに使うこともできますが、is 演算子の方が簡潔で派生型も考慮されます。

// GetType による型チェック(派生型は false になる)
if (obj.GetType() == typeof(string)) { ... }

// is による型チェック(派生型も true になる)
if (obj is string) { ... }

ReferenceEquals() — 参照の同一性

Equals が値ベースにオーバーライドされていても、参照が同一かどうかを確認できます。static メソッドなので、null の比較にも安全に使えます。

var a = new Person { Name = "Alice", Age = 30 };
var b = a;   // 同じ参照
var c = new Person { Name = "Alice", Age = 30 };

Console.WriteLine(ReferenceEquals(a, b)); // True(同じ参照)
Console.WriteLine(ReferenceEquals(a, c)); // False(別のインスタンス)

null チェックにも使えます。

string? s = null;
Console.WriteLine(ReferenceEquals(s, null)); // True

MemberwiseClone() — シャローコピー

protected メソッドなので、クラス内部からしか呼び出せません。フィールドをそのままコピーした新しいインスタンス(シャローコピー)を返します。

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

    public Person Clone() => (Person)MemberwiseClone();
}

var original = new Person { Name = "Alice", Age = 30 };
var copy = original.Clone();

Console.WriteLine(ReferenceEquals(original, copy)); // False(別インスタンス)
Console.WriteLine(copy.Name); // Alice

注意: シャローコピーは参照型フィールドのコピーを行いません。参照型フィールドは元のオブジェクトと同じ参照を指したままになります(ディープコピーにはなりません)。

public class Order
{
    public List<string> Items { get; set; } = new();
    public Order Clone() => (Order)MemberwiseClone();
}

var o1 = new Order();
o1.Items.Add("Apple");

var o2 = o1.Clone();
o2.Items.Add("Banana"); // o1.Items にも反映される!

Console.WriteLine(string.Join(", ", o1.Items)); // Apple, Banana

object 型への代入(ボックス化)

object 型にはあらゆる型のインスタンスを代入できます。

object obj = "Hello";
object num = 42;       // 値型はボックス化される
object flag = true;

値型(int, bool, struct など)を object 型に代入すると**ボックス化(boxing)**が発生し、ヒープ上にコピーが作成されます。パフォーマンスが重要な箇所では多用を避けてください。

int value = 42;
object boxed = value;       // ボックス化(ヒープにコピー)
int unboxed = (int)boxed;   // アンボックス化(型を明示する必要がある)

まとめ

メソッド オーバーライド よくある用途
ToString() 推奨 デバッグ出力、ログ、$"..." 補間
Equals() 値等値が必要なら必須 コレクションのキー比較、== の挙動変更
GetHashCode() Equals と常にセット Dictionary・HashSet の正確な動作
GetType() 不可 リフレクション、型の確認
ReferenceEquals() 不可(static) 参照の同一性確認、null チェック
MemberwiseClone() 通常不要 クローンメソッドの実装

Equals と GetHashCode は常にセットでオーバーライドすること、MemberwiseClone はシャローコピーであることの 2 点が特に重要な注意点です。

C# .NET Object 継承 オーバーライド Equals GetHashCode
← [C#] is と as キーワードを整理する — 型チェック・安全なキャスト・パターンマッチングの使い方 [C#] System.Exception を体系的に理解する — プロパティ・メソッド・実務上の注意点 →

Related Posts

  • [C#] メンバーのシャドーイング(hiding) — new キーワードで基底クラスのメンバーを隠す Apr 29, 2026
  • [C#] sealed の設計戦略 — クラスを「継承させない」という積極的な判断 Apr 26, 2026
  • [C#] 多重継承を許さない言語設計 — Diamond Problem と C++ の経験から考える Apr 25, 2026
  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026

Table of Contents

  • System.Object の役割
  • メソッド一覧
  • ToString() — 文字列表現
    • オーバーライドの例
  • Equals() — 等値比較
    • オーバーライドの例
    • Equals オーバーライドの注意点
  • GetHashCode() — ハッシュコード
    • 実装の指針
  • GetType() — 型情報の取得
  • ReferenceEquals() — 参照の同一性
  • MemberwiseClone() — シャローコピー
  • object 型への代入(ボックス化)
  • まとめ

Recent Posts

  • [C#] Finalizable & Disposable パターン実践 — Dispose パターンの完全形 May 13, 2026
  • [C#] Disposable Objects — IDisposable / Dispose() と using 構文 May 12, 2026
  • [C#] Finalizable Objects — Finalize() の役割と使いどころ May 11, 2026
  • [C#] System.GC クラスを整理する — ガベージコレクションを制御するための API May 10, 2026
  • [C#] IComparable と IComparer — オブジェクトの順序比較と複数ソート戦略 May 9, 2026

Categories

  • C#63
  • .NET62
  • AWS27
  • Laravel16
  • Linux15
  • MySQL9
  • Apache8
  • PHP8
  • DynamoDB6
  • セキュリティ6
  • Nginx5
  • WordPress4
  • インフラ4
  • Hugo3
  • .NET Framework1
  • Aurora1
  • Filament1
  • Git1
  • SQS1

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • Apache
  • Code Snippet
  • DynamoDB
  • NoSQL
  • PHP-FPM
  • RDS
  • パフォーマンス
  • DoS
  • Nginx
  • Windows
  • WordPress
  • メモリ管理
  • 監視
  • 設計
  • Amazon Linux 2023
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • OPCache
  • Webサーバー
  • オブジェクト指向
  • クラス設計
  • コレクション
  • デザインパターン
  • パターンマッチング
  • 継承
  • 認可
  • Aurora
  • Blade
  • Grafana
  • Hugo
  • InfluxDB
  • Policy
  • Record
  • SSG
  • インターフェース
  • エラーハンドリング
  • カプセル化
  • ガベージコレクション
  • モニタリング
  • 例外
Powered by Hugo & Explore Theme.