はじめに
C#ではメソッドを拡張することができますが、F#でも同様にメソッドを拡張することができます。加えて、F#ではメソッドだけではなく、プロパティやイベントなどのメンバーを既存のクラス(type)に追加することができます。今回はこのクラスの拡張について解説したいと思います。
クラスの拡張
F#のモジュールは複数のファイルにまたがることができません。しかし、このクラスの拡張を使用することで、長い1つのファイルを作成することなく各メンバーを記述することが可能になります。
//組み込み拡張 type クラス名 with member セルフ識別子.メンバー名 = 本体 ... [ end ] //オプショナル拡張 module モジュール名 = type 完全修飾クラス名 with member セルフ識別子.メンバー名 = 本体 ... [ end ]
クラスの拡張には2種類あり、1つは組み込み拡張と呼ばれ、拡張されるクラスと同一名前空間、同一モジュール、同一ソースファイル、同一アセンブリ内に記述される拡張です。もう1つはオプショナル拡張と呼ばれ、拡張されるクラスのモジュール、名前空間、もしくはアセンブリの外で表されます。
オプショナル拡張はモジュール内で定義される必要があり、使用するためにはそのモジュールをopenで読み込む必要があります。組み込み拡張はクラスがリフレクションによって分析されてからクラスに現れるようになります。
メソッドの拡張
C#同様に、F#はメソッド拡張をサポートします。C#とは構文が違うだけではなく、F#のクラス拡張はインスタンスメンバーにも、静的(static)メンバーにも適用できます。
C#3.0で導入された拡張メソッドとF#におけるメソッドの拡張方法を比較してみたいと思います。
例として、System.Stringクラスに値がNULL(もしくは空)かどうか判断させるメソッドIsNullorEmpを追加してみましょう。
using System; using testNSA; //※2 拡張メソッドが定義された名前空間をスコープに入れる //拡張メソッドの定義 namespace testNSA { public static class testExt //メソッド拡張用にクラスを作成 { public static bool IsNullorEmp(this string s) //※1 拡張メソッド定義部分。拡張されるクラスをパラメータとしてthisの後に記述 { return (s == null || s.Length == 0); } } } namespace testNSB { class Program { static void Main(string[] args) { string testStr = null; //※3 System.Stringクラスのインスタンス作成 if (testStr.IsNullorEmp ()) //※4 拡張したメソッドを呼び出す { Console.WriteLine("NULLか空です。"); } } } }
まずはじめに、C#の例を見てください。メソッド拡張を定義する名前空間testNSAに追加するメソッドとその仕様を定義しています(※1)。そして、その拡張メソッドを定義した名前空間(リスト1ではtestNSA)をusingでスコープに入れる(※2)ことで、System.Stringクラスのインスタンス(※3)は新しく追加されたメソッドを呼び出す(※4)ことができるようになります。
では、これをF#で行ってみましょう。
open System type String with //※1 System 名前空間をスコープに取り込んでない場合は、System.Stringに。 member this.IsNullorEmp() = //※2 追加するメソッド (this = null || this.Length = 0) //※3 let a = string(null);; //※4 テスト用インスタンス作成 if( a.IsNullorEmp()) then Console.WriteLine("NULLか空です。");; //※5
▼
type String with member IsNullorEmp : unit -> bool val a : string = "" > NULLか空です。 val it : unit = ()
System.String(クラス)に値がNull(もしくは空)かどうかを判断するメソッドを追加するF#のオプショナル拡張の例です。
typeの後ろにメソッド拡張するクラスを指定し(※1 この場合System.String)、その後に追加するメンバー(メソッド)を定義(※2)します。thisはセルフ修飾子ですので、任意の文字を入れてください。セルフ修飾子の後のドットに続き、メンバー名を指定して、メソッドの仕様を定義します。メソッドを拡張するために新たなクラスを作成する必要がありません。
リストの例では、IsNullorEmpメソッドはパラメータがnullもしくは長さが0の場合に、trueを返します(※3)。後半2行でこの追加されたメソッドを実際に呼び出しています。String型のインスタンスaを作成(※4)すると、a経由で追加されたメソッドを呼び出すことが可能であることが確認できます。ifを用いた条件文で、a.IsNullorEmpがtrueの場合に「NULLです。」と表示させるよう定義(※5)してます。
Stringクラスにこのメソッドが追加されたかどうかは、下記のようにインテリセンスのステートメントの入力候補としてそのメソッドが表示されることによっても確認することができます。
例で使用した、if文(条件式)の構文は以下のようになります。
if条件式 then式1 [ else 式2 ]
条件式がtrueの場合式1を実行し、falseの場合はelse以降を実行します。