屬性 (F#)
「屬性」(Property) 是代表與物件關聯之值的成員。
// Property that has both get and set defined.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with [accessibility-modifier] get() =
get-function-body
and [accessibility-modifier] set parameter =
set-function-body
// Alternative syntax for a property that has get and set.
[ attributes-for-get ]
[ static ] member [accessibility-modifier-for-get] [self-identifier.]PropertyName =
get-function-body
[ attributes-for-set ]
[ static ] member [accessibility-modifier-for-set] [self-identifier.]PropertyName
with set parameter =
set-function-body
// Property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName =
get-function-body
// Alternative syntax for property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with get() =
get-function-body
// Property that has set only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with set parameter =
set-function-body
備註
屬性表示物件導向設計程式中的 "Has a" 關聯性,代表與物件執行個體相關聯的資料 (靜態屬性則是與型別相關聯)。
您可以使用 member 關鍵字、表示目前執行個體的自我識別項值,以及屬性名稱來宣告屬性 (Property)。 這個宣告式語法後面接著指定 get 和 set 方法 (也稱為「存取子」(Accessor)) 的語法。 以下顯示各種用於讀取/寫入、唯讀和唯寫屬性 (Property) 的語法形式。 對於唯讀屬性 (Property),您只需定義 get 方法;對於唯寫屬性 (Property),則只需定義 set 方法。 請注意,當屬性 (Property) 同時有 get 和 set 存取子時,替代語法可讓您對每個存取子指定不同的屬性 (Attribute) 和存取範圍修飾詞,如下列程式碼所示。
// A read-only property.
member this.MyReadOnlyProperty = myInternalValue
// A write-only property.
member this.MyWriteOnlyProperty with set (value) = myInternalValue <- value
// A read-write property.
member this.MyReadWriteProperty
with get () = myInternalValue
and set (value) = myInternalValue <- value
保存屬性資料的私用值稱為「備份存放區」(Backing Store)。 與其他語言不同,F# 不提供建立屬性隱含備份存放區的機制,因此您必須明確定義備份存放區,一般方式是使用可變 let 繫結,如下所示。
type MyClass(x : string) =
let mutable myInternalValue = x
member this.MyProperty
with get() = myInternalValue
and set(value) = myInternalValue <- value
對於同時有 get 和 set 方法的讀取/寫入屬性,get 和 set 的順序可以相反。 此外,您也可以分別為 get 和 set 提供以下所示的語法,而不使用合併語法。 如有需要,這麼做就能更容易地將個別 get 或 set 方法標記為註解。 這個合併語法的替代方法如下列程式碼所示。
member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value
屬性可以是類別、結構、已區分之聯集、記錄、介面和型別擴充的成員,也可以在物件運算式中定義。
屬性 (Attribute) 可以套用至屬性 (Property), 只要在屬性 (Property) 前面的另一行撰寫屬性 (Attribute) 即可。 如需詳細資訊,請參閱屬性 (F#)。
屬性預設都是公用屬性。 存取範圍修飾詞也可以套用至屬性。 若要套用存取範圍修飾詞,而且是要同時套用至 get 和 set 方法時,請在屬性名稱前面加上存取範圍修飾詞;如果是要為每個存取子套用不同的存取範圍,請在 get 和 set 關鍵字前面加上存取範圍修飾詞。 accessibility-modifier 可以是下列其中一項:public、private、internal。 如需詳細資訊,請參閱存取控制 (F#)。
每次存取屬性時,都會執行屬性實作。
靜態屬性和執行個體屬性
屬性可以是靜態或執行個體屬性。 您可以在沒有執行個體的情況下叫用靜態屬性,並且用於與型別 (而非個別物件) 相關聯的值。 對於靜態屬性,請省略自我識別項, 因為只有執行個體屬性才需要自我識別項。
下列靜態屬性定義是根據靜態欄位 myStaticValue 做為屬性備份存放區的案例而設定。
static member MyStaticProperty
with get() = myStaticValue
and set(value) = myStaticValue <- value
屬性也可以類似陣列,在此情況下稱為「索引屬性」(Indexed Property)。 如需詳細資訊,請參閱索引屬性 (F#)。
屬性的型別附註
在許多情況下,編譯器都有足夠資訊可以從備份存放區型別來推斷屬性型別,但是您也可以加入型別附註明確設定型別。
// To apply a type annotation to a property that does not have an explicit
// get or set, apply the type annotation directly to the property.
member this.MyProperty1 : int = myInternalValue
// If there is a get or set, apply the type annotation to the get or set method.
member this.MyProperty2 with get() : int = myInternalValue
使用屬性 set 存取子
您可以使用 <- 運算子,設定可提供 set 存取子的屬性。
// Assume that the constructor argument sets the initial value of the
// internal backing store.
let mutable myObject = new MyType(10)
myObject.MyProperty <- 20
printfn "%d" (myObject.MyProperty)
輸出為 20。
抽象屬性
屬性可以是抽象的。 如同方法,「抽象」(Abstract) 只表示屬性有相關聯的虛擬分派。 抽象屬性可以是真正抽象的,也就是相同類別中沒有定義。 因此,包含這類屬性的類別就是抽象類別。 此外,抽象也可以只表示屬性是虛擬的,在此情況下相同類別中必須有定義。 請注意,抽象屬性不可以是私用屬性,而且如果一個存取子是抽象存取子,另一個也必須是抽象存取子。 如需抽象類別的詳細資訊,請參閱抽象類別 (F#)。
// Abstract property in abstract class.
// The property is an int type that has a get and
// set method
[<AbstractClass>]
type AbstractBase() =
abstract Property1 : int with get, set
// Implementation of the abstract property
type Derived1() =
inherit AbstractBase()
let mutable value = 10
override this.Property1 with get() = value and set(v : int) = value <- v
// A type with a "virtual" property.
type Base1() =
let mutable value = 10
abstract Property1 : int with get, set
default this.Property1 with get() = value and set(v : int) = value <- v
// A derived type that overrides the virtual property
type Derived2() =
inherit Base1()
let mutable value2 = 11
override this.Property1 with get() = value2 and set(v) = value2 <- v