型別擴充 (F#)
型別擴充可讓您將新成員加入至先前定義的物件型別。
// Intrinsic extension.
type typename with
member self-identifier.member-name =
body
...
[ end ]
// Optional extension.
type typename with
member self-identifier.member-name =
body
...
[ end ]
備註
型別擴充有兩種,其語法和行為稍有不同。「內建擴充」(Intrinsic Extension) 是出現在與所擴充型別相同的命名空間或模組、相同原始檔,或相同組件 (DLL 或可執行檔) 中的擴充。「選擇性擴充」(Optional Extension) 是出現在所擴充型別之原始模組、命名空間或組件外部的擴充。當反映檢查型別時,型別上會出現內建擴充,但不會出現選擇性擴充。選擇性擴充必須是在模組中,而且只有在包含擴充的模組開啟時才會在範圍內。
在先前的語法中,typename 表示要擴充的型別。任何可存取的型別都可以擴充,但是型別名稱必須是實際的型別名稱,而不是型別縮寫。您可以在一個型別擴充中定義多個成員。self-identifier 表示叫用的物件執行個體,就像一般成員一樣。
end 在輕量型語法中是選擇性關鍵字。
使用型別擴充中定義的成員時,就像使用類別型別上的其他成員一樣。如同其他成員,這些成員可以是靜態或執行個體成員。這些方法也稱為「擴充方法」(Extension Method),而屬性則稱為「擴充屬性」(Extension Property),以此類推。選擇性擴充成員會編譯為靜態成員,其物件執行個體會隱含傳遞做為第一個參數。不過,根據他們的宣告方式,他們會表現得向執行個體成員或靜態成員。隱含擴充成員是包含做為型別的成員,因此使用時不受限制。
擴充方法不可以是虛擬或抽象方法。它們可以多載同名的其他方法,但是編譯器會在進行模稜兩可的呼叫時提供不可擴充方法的偏好設定。
如果一個型別有多個內建型別擴充,則所有成員都必須是唯一。對於選擇性型別擴充,在相同型別但不同型別擴充中的成員可以有相同名稱。只有在用戶端程式碼開啟兩個定義了相同成員名稱的不同範圍時,才會發生語意模糊錯誤。
在下列範例中,模組中的型別有內建型別擴充。對於該模組外的用戶端程式碼,就各方面來說,此型別擴充會顯示為型別的一般成員。
module MyModule1 =
// Define a type.
type MyClass() =
member this.F() = 100
// Define type extension.
type MyClass with
member this.G() = 200
module MyModule2 =
let function1 (obj1: MyModule1.MyClass) =
// Call an ordinary method.
printfn "%d" (obj1.F())
// Call the extension method.
printfn "%d" (obj1.G())
您可以使用內建型別擴充將型別定義分為不同區段。這在管理大型型別定義時很有用,例如,將編譯器產生的程式碼和撰寫的程式碼分開,或者將不同人員所建立或與不同功能關聯的程式碼群組在一起。
在下列範例中,選擇性型別擴充會以呼叫靜態成員 Parse 的擴充方法 FromString 來擴充 System.Int32 型別。testFromString 方法會示範呼叫新成員的方式,就如同呼叫任何執行個體成員一樣。
// Define a new member method FromString on the type Int32.
type System.Int32 with
member this.FromString( s : string ) =
System.Int32.Parse(s)
let testFromString str =
let mutable i = 0
// Use the extension method.
i <- i.FromString(str)
printfn "%d" i
testFromString "500"
新執行個體成員看起來就像 IntelliSense 中 Int32 型別的任何其他方法,但是只有在包含擴充的模組已開啟或在範圍內才會如此。