拡張プロパティ(F#)

F#では既存の型を拡張して、プロパティを追加することができます。

今回はいくつか使い方を紹介します。

Getterのみ

Listを拡張してみます。

ジェネリックなクラスは拡張できないので、ベースのIListを拡張します。

Countの2倍の値を返すCountDoubleを実装してみます。

open System.Collections
open System.Collections.Generic

type IList with
    member this.DoubleCount = this.Count * 2

[<EntryPoint>]
let main argv = 
    let x = List<int>([ 1; 2; 3 ])
    let s = x.DoubleCount // 6
    0


Setter対応

F#基本的にImmutableであるため、Setterを実装することは稀です。

ただ、利用する機会がある可能性があるので実装してみます。

型拡張は原理的にはstaticな関数を追加しているだけなので、fieldを追加することができません。

そこでインスタンスをキーとして状態を保持するDictionaryを用意します。

しかしDictionaryを利用するとインスタンスが参照され続けるので、弱参照で保持するConditionalWeakTableを利用します。

open System.Collections
open System.Collections.Generic
open System.Runtime.CompilerServices

type ListState = { mutable Name : string }

let initialListState = { Name = "name" }

let listStates = ConditionalWeakTable<IList, ListState>()

let getListState x = listStates.GetValue(x, ConditionalWeakTable.CreateValueCallback(fun _ -> initialListState))

type IList with
    member this.Name with get()      = (getListState this).Name
                     and  set(value) = (getListState this).Name <- value

[<EntryPoint>]
let main argv = 
    let x = List<int>([ 1; 2; 3 ])
    x.Name <- "NewList"
    printfn "%s" x.Name
    0