bucket-sort logo bucket-sort

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

  • Posts
  • About
  • Contact
  1. Home
  2. All Posts
  3. [C#] カスタム型変換(Custom Type Conversions)の使い方 — explicit と implicit を使いこなす

[C#] カスタム型変換(Custom Type Conversions)の使い方 — explicit と implicit を使いこなす

Jun 6, 2026 C# , .NET bucket-sort

C# では、自作型に対して変換演算子(conversion operator)を定義することで、キャスト構文 (TargetType)value や暗黙的な代入で型を変換できるようになります。

この記事では Rectangle と Square の 2 つの構造体を例に、次の 4 つを順に説明します。

  1. explicit と implicit の違い
  2. カスタム変換ルーチンの作成
  3. explicit 変換の追加例(int との相互変換)
  4. implicit 変換の定義

explicit と implicit の違い

変換演算子には explicit(明示的)と implicit(暗黙的)の 2 種類があります。

キーワード 呼び出し方 特徴
explicit キャスト構文 (型)値 が必須 情報の欠落や精度の低下が起こりうる変換に使う
implicit キャストなしで代入できる 安全な変換(情報が失われない)に使う
// explicit の場合: キャストが必要
Square sq = (Square)rect;

// implicit の場合: キャスト不要
Rectangle rect = sq;

explicit は「コンパイラに対して『この変換は意図的だ』と明示する」もので、精度の低下やデータの欠落が想定されるときに使います。implicit は「自然に変換できる」ときに使いますが、暗黙的に変換されるため、気づかないうちに変換が走ることに注意が必要です。

カスタム変換ルーチンの作成

まず Rectangle(長方形)と Square(正方形)の 2 つの構造体を定義します。正方形は縦横が等しいため、長方形から正方形に変換するときは高さだけを使います。

public struct Rectangle
{
    public int Width { get; set; }
    public int Height { get; set; }

    public override string ToString() => $"Rectangle [Width={Width}, Height={Height}]";
}

public struct Square
{
    public int Length { get; set; }

    // Rectangle → Square の明示的変換
    public static explicit operator Square(Rectangle r)
    {
        Square s = new Square { Length = r.Height };
        return s;
    }

    public override string ToString() => $"Square [Length={Length}]";
}

explicit にしているのは、長方形を正方形に変換する際に幅(Width)の情報が失われるからです。変換後の正方形は高さ(Height)のみを辺の長さとして使うため、「情報の欠落が伴う変換」として明示的なキャストを要求しています。

var rect = new Rectangle { Width = 20, Height = 10 };

// キャストが必要(explicit のため)
Square sq = (Square)rect;

Console.WriteLine(rect); // Rectangle [Width=20, Height=10]
Console.WriteLine(sq);   // Square [Length=10]

キャストを書かずに代入しようとするとコンパイルエラーになります。

Square sq = rect; // コンパイルエラー: 明示的なキャストが必要

explicit 変換の追加

正方形と int の間でも変換できると便利です。たとえば Square sq = (Square)90; のように整数から正方形を作ったり、int side = (int)sq; のように辺の長さを整数として取り出したりできるようにします。

public struct Square
{
    public int Length { get; set; }

    // Rectangle → Square の変換(前節と同じ)
    public static explicit operator Square(Rectangle r)
    {
        Square s = new Square { Length = r.Height };
        return s;
    }

    // int → Square の明示的変換
    public static explicit operator Square(int sideLength)
    {
        Square newSq = new Square { Length = sideLength };
        return newSq;
    }

    // Square → int の明示的変換
    public static explicit operator int(Square s) => s.Length;

    public override string ToString() => $"Square [Length={Length}]";
}
// int → Square
Square sq2 = (Square)90;
Console.WriteLine(sq2); // Square [Length=90]

// Square → int
int side = (int)sq2;
Console.WriteLine(side); // 90

int → Square を explicit にしているのは、「整数をそのまま正方形の辺の長さとして扱う」という意図的な変換であることをコード上で示したいためです。暗黙的に変換されると、Square s = someInt; のような代入が意図せず成立してしまい、読みづらくなります。

implicit 変換の定義

逆に、正方形を長方形として扱う変換は「情報の欠落がない」ため implicit で定義できます。正方形は縦横が等しいので、長方形の Width と Height を両方埋めることができます。今回は幅を辺の長さの 2 倍にする仕様とします。

public struct Rectangle
{
    public int Width { get; set; }
    public int Height { get; set; }

    // Square → Rectangle の暗黙的変換
    public static implicit operator Rectangle(Square s)
    {
        Rectangle r = new Rectangle
        {
            Height = s.Length,
            Width = s.Length * 2   // 幅は辺の長さの 2 倍とする仕様
        };
        return r;
    }

    public override string ToString() => $"Rectangle [Width={Width}, Height={Height}]";
}

implicit なので、キャストを書かずにそのまま代入できます。

Square s3 = new Square { Length = 83 };

// キャスト不要(implicit のため)
Rectangle rect2 = s3;

Console.WriteLine(s3);     // Square [Length=83]
Console.WriteLine(rect2);  // Rectangle [Width=166, Height=83]

もちろん、明示的にキャストして書くことも問題なく動作します。

Rectangle rect3 = (Rectangle)s3; // これも動く

構造体をまとめると

ここまでの定義をまとめた完全なコードです。

public struct Rectangle
{
    public int Width { get; set; }
    public int Height { get; set; }

    // Square → Rectangle(implicit)
    public static implicit operator Rectangle(Square s)
    {
        return new Rectangle
        {
            Height = s.Length,
            Width = s.Length * 2
        };
    }

    public override string ToString() => $"Rectangle [Width={Width}, Height={Height}]";
}

public struct Square
{
    public int Length { get; set; }

    // Rectangle → Square(explicit: Width の情報が失われる)
    public static explicit operator Square(Rectangle r)
    {
        return new Square { Length = r.Height };
    }

    // int → Square(explicit: 意図的な変換であることを明示)
    public static explicit operator Square(int sideLength)
    {
        return new Square { Length = sideLength };
    }

    // Square → int(explicit)
    public static explicit operator int(Square s) => s.Length;

    public override string ToString() => $"Square [Length={Length}]";
}
// Rectangle → Square(explicit)
var rect = new Rectangle { Width = 20, Height = 10 };
Square sq1 = (Square)rect;
Console.WriteLine(sq1);   // Square [Length=10]

// int → Square(explicit)
Square sq2 = (Square)90;
Console.WriteLine(sq2);   // Square [Length=90]

// Square → int(explicit)
int side = (int)sq2;
Console.WriteLine(side);  // 90

// Square → Rectangle(implicit)
Square s3 = new Square { Length = 83 };
Rectangle rect2 = s3;
Console.WriteLine(rect2); // Rectangle [Width=166, Height=83]

まとめ

変換 キーワード 理由
Rectangle → Square explicit Width の情報が失われる
int → Square explicit 意図的であることを明示したい
Square → int explicit 意図的であることを明示したい
Square → Rectangle implicit 情報の欠落がなく自然な変換

変換演算子の使い分けの基本は「情報が失われる可能性があれば explicit、安全に変換できるなら implicit」です。implicit は書く側には便利ですが、読む側が変換に気づきにくいため、本当に自然な変換にだけ使うのが安全です。

C# .NET 型変換 Explicit Implicit Custom Type Conversions Operator
← [C#] 演算子オーバーロード(Operator Overloading)の使い方 — 二項演算子・単項演算子・等価演算子・比較演算子 [C#] 拡張メソッド(Extension Methods)の使い方 →

Related Posts

  • [C#] is と as キーワードを整理する — 型チェック・安全なキャスト・パターンマッチングの使い方 Apr 30, 2026
  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026
  • [C#] 属性でコードに意味を与える Jul 8, 2026
  • [C#] 外部アセンブリを読み込み実行時に型を呼び出す Jul 7, 2026

Table of Contents

  • explicit と implicit の違い
  • カスタム変換ルーチンの作成
  • explicit 変換の追加
  • implicit 変換の定義
  • 構造体をまとめると
  • まとめ

Recent Posts

  • [C#] プラグインで拡張できるアプリケーションを設計する Jul 9, 2026
  • [C#] 属性でコードに意味を与える Jul 8, 2026
  • [C#] 外部アセンブリを読み込み実行時に型を呼び出す Jul 7, 2026
  • [C#] リフレクションで型の中身を調べる Jul 6, 2026
  • [C#] 型メタデータとリフレクションの基礎を理解する Jul 5, 2026

Categories

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

Tags

  • C#
  • .NET
  • AWS
  • Laravel
  • コレクション
  • PHP
  • セキュリティ
  • MySQL
  • Linux
  • パフォーマンス
  • Apache
  • System.Collections.Generic
  • デリゲート
  • Code Snippet
  • DynamoDB
  • LINQ
  • NoSQL
  • PHP-FPM
  • RDS
  • System.Collections
  • Windows
  • メモリ管理
  • リフレクション
  • DoS
  • Nginx
  • WordPress
  • メタデータ
  • ラムダ式
  • 監視
  • 設計
  • Amazon Linux 2023
  • Delegate
  • Docker
  • IDisposable
  • Ipset
  • Iptables
  • LINQ to Objects
  • OPCache
  • Pointer
  • Reflection
  • System.Collections.Specialized
  • Unsafe
  • Webサーバー
  • インターフェース
  • オブジェクト指向
  • クラス設計
  • デザインパターン
  • パターンマッチング
  • ポインター
  • 継承
Powered by Hugo & Explore Theme.