クラスキャスト
Midoliy|F#プログラミング

クラスキャストの概要
サンプルでみるアップキャスト
サンプルでみるダウンキャスト

クラスキャストの概要


 F#のクラス(または構造体)は、オブジェクト階層内の型間で相互に変換できます。これはオブジェクト指向プログラミングにおいて重要なポリモーフィズムを実現するために必須といっても過言ではない機能です。キャストには アップキャストダウンキャスト という2種類の方法があります。アップキャストとは、「派生クラスから基底クラスにキャスト」することを指します。また、ダウンキャストは「基底クラスから派生クラスにキャスト」することを指します。
 アップキャストは、基底クラスが派生クラスの継承階層内にある限り、確実に機能します。しかし、ダウンキャストの場合は、オブジェクトが実際に正しい派生型の場合にのみ成功します。
 F#では、アップキャストをする際には :> 演算子を利用し、ダウンキャストする際には :?> 演算子を利用します。


サンプルでみるアップキャスト


 多くのオブジェクト指向言語では、アップキャストは暗黙的に行われます。しかし、F#では、規則が少し異なります。オブジェクト型のメソッドに引数を渡すと、アップキャストが自動的に適用されます。ただし、モジュール内のlet束縛されている関数の場合は、パラメータがフレキシブル型で宣言されていない限り、アップキャストは自動では行われません。
 :> 演算子でのキャスト成功は、コンパイル時に型が決定されていることを意味し、静的にキャストが行われます。つまり、アップキャスト利用時にコンパイルが正常にされた場合、それは有効なキャストであり、実行時に失敗する可能性はありません。
 アップキャストをしたい場合に、:> 演算子ではなく、upcast 演算子を利用することも可能です。upcast演算子は以下のような構文となっています。
upcast expression

 upcast演算を使用すると、コンパイラはコンテキストから変換先の型を推測しようとします。コンパイラが変換先の型を判別できない場合、コンパイルエラーとなります。

// =========================================================
// アップキャストのサンプル
// =========================================================
// 基底クラス
type Base () = class
abstract member Function: unit -> unit
default x.Function () = printfn "default: Base.Function()"
end
// 派生クラス
type Derived () = class
inherit Base ()
override x.Function () = printfn "Derived.Function()"
end
// 派生クラスをインスタンス化
let d1:Derived = new Derived ()
// Baseクラスへアップキャスト(1)
let base1 = d1 :> Base
// Baseクラスへアップキャスト(2)
let base2:Base = upcast d1
view raw upcast1.fs hosted with ❤ by GitHub


サンプルでみるダウンキャスト


 :?> 演算子でのキャスト成否は実行時に決定されます。つまり、動的にキャストが行われます。:?> 演算子でのキャストはコンパイル時にはチェックされません。しかし、実行時には指定された方へのキャストをしようと試みます。オブジェクトがキャスト先の型と互換性がある場合に、キャストが成功します。互換性がない場合には、InvalidCastException が発生します。
 ダウンキャストをしたい場合に、:?> 演算子ではなく、downcast 演算子を利用することも可能です。downcast演算子は以下のような構文となっています。
downcast expression

以下は、ダウンキャストの簡単なサンプルになります。

// =========================================================
// ダウンキャストのサンプル
// =========================================================
// 基底クラス
type Base () = class
abstract member Function: unit -> unit
default x.Function () = printfn "default: Base.Function()"
end
// 派生クラス
type Derived () = class
inherit Base ()
override x.Function () = printfn "Derived.Function()"
end
// 基底クラスをインスタンス化
let base1:Base = new Base ()
// Derivedクラスへダウンキャスト(1)
let d1 = base1 :?> Derived
// Derivedクラスへダウンキャスト(2)
let d2:Derived = downcast base1
view raw downcast1.fs hosted with ❤ by GitHub