C#における型変換の完全ガイド

型変換の基本概念

異なる型の変数間で値を代入する場合、ソース変数の型をターゲット変数の型に変換する必要があります。変換とは、ある型の値を受け取り、それを別の型の等価な値として使用するプロセスです。変換後の値はソース値と同じデータを参照しますが、その型はターゲット型となります。

short sourceValue = 5;
sbyte targetValue = 10;
targetValue = (sbyte)sourceValue; // キャスト式による明示的変換

暗黙的変換

データ損失や精度の低下を伴わない型変換は、コンパイラによって自動的に行われます。これを暗黙的変換と呼びます。例えば、8ビットの値を16ビットの変数に代入する場合などが該当します。

符号なし型の変換

より小さな符号なし型から大きな符号なし型へ変換する際、ターゲット型の上位ビットはゼロで埋められます。これは「ゼロ拡張」と呼ばれます。

符号付き型の変換

符号付き型をより大きな型に変換する場合、追加の上位ビットはソース値の符号ビットで埋められます。これにより、変換後の値の正負と大きさが正しく維持されます。これを「符号拡張」と呼びます。

明示的変換とキャスト

暗黙的変換が許可されていない場合、データ損失のリスクを承知の上で明示的に変換を行う必要があります。これをキャストと呼び、キャスト式を使用して記述します。

sbyte result = (sbyte)sourceValue;

キャストを使用すると、データ損失が発生する可能性があります。

// データが収まる場合
ushort largeVal = 10;
byte smallVal = (byte)largeVal; // 結果: 10

// データが収まらない場合
largeVal = 1365;
smallVal = (byte)largeVal; // 結果: 85 (オーバーフロー)

変換の種類

標準的な変換に加え、ユーザー定義の暗黙的・明示的変換を作成できます。また、ボックス化と呼ばれる特別な変換により、任意の値型を object 型や System.ValueType 型に変換できます。ボックス化解除は、ボックス化された値を元の型に戻す操作です。

数値型の変換

数値型は他の数値型へ変換可能ですが、変換の種類(暗黙的または明示的)は型の組み合わせによって異なります。

暗黙的な数値変換

変換元の型から変換先の型へ、データ損失なしに暗黙的に変換できるパスが存在する場合、暗黙的変換が可能です。存在しない場合は明示的変換が必要です。

オーバーフローチェックコンテキスト

checked 演算子およびステートメントを使用すると、整数型の変換時にオーバーフローが発生したかどうかを検出できます。

  • checked: オーバーフロー時に OverflowException がスローされます。
  • unchecked: オーバーフローが発生しても例外はスローされず、結果は切り捨てられます。

checked/unchecked 演算子

式に対してオーバーフローチェックを適用します。

ushort val = 2000;
byte uncheckedResult = unchecked((byte)val); // 結果: 208 (データ損失)
byte checkedResult = checked((byte)val);      // OverflowException がスローされる

checked/unchecked ステートメント

コードブロック内のすべての変換に対してオーバーフローチェックを適用します。ネスト可能です。

checked
{
    unchecked
    {
        // ここは unchecked コンテキスト
    }
    // ここは checked コンテキスト
}

明示的な数値変換

整数型から整数型

checked コンテキストではデータ損失時に例外がスローされます。unchecked コンテキストでは、上位ビットが切り捨てられます。

浮動小数点数から整数型

小数部分は切り捨てられます。checked コンテキストで結果がターゲット型の範囲外の場合、例外がスローされます。

float fVal = 10.9f;
int iVal = (int)fVal; // 結果: 10

decimal から整数型

結果がターゲット型の範囲外の場合、checked かどうかにかかわらず例外がスローされます。

double から float

double 値は最も近い float 値に丸められます。値が小さすぎる場合はゼロ、大きすぎる場合は正または負の無限大になります。

float/double から decimal

値が小さすぎる場合は0になり、大きすぎる場合は例外がスローされます。

decimal から float/double

この変換は常に成功しますが、精度が失われる可能性があります。

参照型の変換

参照型オブジェクトは、参照とデータの2つの部分で構成されます。参照変換は、ヒープ上の同じ場所を指す参照を返しますが、その参照を別の型としてマークします。

暗黙的な参照変換

  • すべての参照型は object 型に暗黙的に変換できます。
  • 任意のインターフェースは、そのインターフェースが継承しているインターフェースに暗黙的に変換できます。
  • クラスは、継承チェーン内の任意の基底クラスや実装しているインターフェースに暗黙的に変換できます。

明示的な参照変換

基底クラスから派生クラスへの変換など、ダウンキャストは明示的な参照変換です。不適切な変換はコンパイラによって許可されますが、実行時に例外がスローされます。

BaseClass baseObj = new BaseClass();
DerivedClass derivedObj = (DerivedClass)baseObj; // 実行時エラー

有効な明示的参照変換

実行時に成功する明示的変換には以下のケースがあります。

  1. 変換が不要な場合(アップキャストなど)。
  2. ソース参照が null の場合。
  3. ソース参照が指す実際のデータが、ターゲット型に安全に変換できる場合。
DerivedClass d = new DerivedClass();
BaseClass b = d;           // 暗黙的変換
DerivedClass d2 = (DerivedClass)b; // 有効な明示的変換

ボックス化

値型はデフォルトでヒープ上にオブジェクトコンポーネントを持ちませんが、ボックス化によって値型の値をヒープ上の完全な参照型オブジェクトとして扱うことができます。ボックス化は暗黙的な変換です。

int number = 12;
object boxedObj = number; // ボックス化

ボックス化はコピーを作成します。ボックス化後、元の値型とボックス化されたコピーは独立して操作できます。

ボックス化解除

ボックス化解除は明示的な変換です。ボックス化されたオブジェクトがターゲットの値型と互換性があるか確認し、その値をコピーします。

int original = 10;
object boxed = original;
int unboxed = (int)boxed; // ボックス化解除

ユーザー定義の変換

クラスまたは構造体に対して、カスタムの暗黙的または明示的変換を定義できます。

構文

// 暗黙的変換
public static implicit operator TargetType(SourceType source)
{
    return new TargetType(source);
}

// 明示的変換
public static explicit operator TargetType(SourceType source)
{
    return new TargetType(source);
}

制約

  • クラスまたは構造体に対してのみ定義可能です。
  • ソース型とターゲット型は異なり、継承関係になく、どちらもインターフェースや object 型であってはなりません。
  • 変換演算子はソース型またはターゲット型のメンバーである必要があります。

複数ステップの変換

ユーザー定義変換は、標準変換の前後に最大1回ずつ組み合わせて使用できます。変換チェーンには最大1つのユーザー定義変換しか含めることができません。

is 演算子

is 演算子は、変換が成功するかどうかを確認するために使用します。参照変換、ボックス化、ボックス化解除に対して使用できますが、ユーザー定義変換には使用できません。

Employee emp = new Employee();
if (emp is Person)
{
    Person p = (Person)emp;
    // 変換成功時の処理
}

as 演算子

as 演算子はキャストに似ていますが、変換に失敗した場合に例外をスローせず null を返します。ターゲット型は参照型である必要があります。ユーザー定義変換には使用できません。

Employee emp = new Employee();
Person p = emp as Person;
if (p != null)
{
    // 変換成功時の処理
}

タグ: C# 型変換 キャスト ボックス化 参照型

5月16日 18:02 投稿