属性 (F#)
“属性”是表示与对象关联的值的成员。
// 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
备注
属性在面向对象的编程中代表“具有”关系,表示与对象实例关联的数据,或者,对于静态属性,则表示与类型关联的数据。
您通过使用 member 关键字、表示当前实例的自我标识符值以及属性的名称来声明属性。 此声明性语法后跟指定 get 和 set 方法(也称为“访问器”)的语法。 所示语法的各种形式用于读/写、只读和只写属性。 对于只读属性,只定义 get 方法;对于只写属性,只定义 set 方法。 请注意,当属性同时具有 get 和 set 访问器时,您可以利用可选语法指定对于每个访问器不同的特性和可访问性修饰符,如下面的代码中所示。
// 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
容纳属性数据的私有值称为“后备存储”。 与其他语言不同,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
属性可以是类、结构、可区分联合、记录、接口和类型扩展的成员,并且也可以在对象表达式中定义。
可将特性应用于属性。 若要将特性应用于属性,请在属性前面另起一行编写特性。 有关更多信息,请参见特性 (F#)。
默认情况下,属性是公共属性。 也可以将可访问性修饰符应用于属性。 若要应用可访问性修饰符,如果要将属性同时应用于 get 和 set 方法,请将其添加在紧靠属性名称的前面;如果每个访问器需要不同的可访问性,则将其添加在 get 和 set 关键字前面。 accessibility-modifier 可以是以下值之一:public、private 和 internal。 有关更多信息,请参见访问控制 (F#)。
每次访问一个属性时都会执行属性实现。
静态属性和实例属性
属性可以是静态属性或实例属性。 静态属性可以在没有实例的情况下调用,并且用于与类型(而不是个别对象)关联的值。 对于静态属性,可忽略自我标识符。 自我标识符是实例属性所需要的。
以下静态属性定义基于这样一种方案:您有一个用作属性后备存储的静态字段 myStaticValue。
static member MyStaticProperty
with get() = myStaticValue
and set(value) = myStaticValue <- value
属性也可以像数组一样,在这种情况下,属性称为“索引属性”。 有关更多信息,请参见索引属性 (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。
抽象属性
属性可以是抽象的。 与方法一样,“抽象”只是意味着存在与属性关联的虚拟调度。 抽象属性可以是真正抽象的,也就是说,在同一个类中没有定义。 包含此类属性的类因而也就成为了抽象类。 或者,“抽象”可能只是意味着属性是虚拟的,在这种情况下,同一个类中必须存在定义。 请注意,抽象属性不能为私有属性,并且,如果一个访问器是抽象的,则另一个访问器也必须是抽象的。 有关抽象类的更多信息,请参见抽象类 (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