属性 是表示与对象关联的值的成员。
语法
// Property that has both get and set defined.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with [ attributes-for-get ] [accessibility-modifier] get() =
get-function-body
and [ attributes-for-set ] [accessibility-modifier] set parameter =
set-function-body
// Alternative syntax for a property that has get and set.
[ static ] member [accessibility-modifier-for-get] [self-identifier.]PropertyName
with [ attributes-for-get ] get() =
get-function-body
[ static ] member [accessibility-modifier-for-set] [self-identifier.]PropertyName
with [ attributes-for-set ] 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.
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with [ attributes ] get() =
get-function-body
// Property that has set only.
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with [ attributes ] set parameter =
set-function-body
// Automatically implemented properties.
[ attributes ]
[ static ] member val [accessibility-modifier] PropertyName = initialization-expression [ with get, set ]
注解
属性表示面向对象的编程中的“具有”关系,表示与对象实例关联的数据,或者对于具有该类型的静态属性的数据。
可以通过两种方式声明属性,具体取决于是要显式指定属性的基础值(也称为后盾存储),还是希望允许编译器自动生成后盾存储。 通常,如果属性具有非简单实现,并且当属性只是值或变量的简单包装器时,应使用更明确的方法。 若要显式声明属性,请使用 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
对于具有和getset方法的读/写属性,可以反转其顺序getset。 或者,可以提供仅显示的 get 语法和仅显示的 set 语法,而不是使用组合语法。 这样做可以更轻松地注释掉个人或getset方法(如果这是可能需要执行的作)。 以下代码中显示了使用此组合语法的替代方法。
member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value
保存属性数据的私有值称为 后盾存储。 若要让编译器自动创建后退存储区,请使用关键字 member val,省略自标识符,然后提供表达式来初始化属性。 如果属性是可变的,请包括 with get, set。 例如,以下类类型包括两个自动实现的属性。
Property1 是只读的,初始化为提供给主构造函数的参数,并且 Property2 是初始化为空字符串的可设置属性:
type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set
自动实现的属性是类型初始化的一部分,因此必须在任何其他成员定义之前包括它们,就像类型定义中的绑定和let绑定一样do。 请注意,初始化自动实现属性的表达式仅在初始化时计算,而不是每次访问该属性时。 此行为与显式实现的属性的行为形成鲜明对比。 这实际上意味着,用于初始化这些属性的代码将添加到类的构造函数中。 请考虑以下代码,其中显示了此差异:
type MyClass() =
let random = new System.Random()
member val AutoProperty = random.Next() with get, set
member this.ExplicitProperty = random.Next()
let class1 = new MyClass()
printfn $"class1.AutoProperty = %d{class1.AutoProperty}"
printfn $"class1.ExplicitProperty = %d{class1.ExplicitProperty}"
输出
class1.AutoProperty = 1853799794
class1.AutoProperty = 1853799794
class1.ExplicitProperty = 978922705
class1.ExplicitProperty = 1131210765
上述代码的输出显示重复调用时的值 AutoProperty 保持不变,而 ExplicitProperty 每次调用时都会更改。 这演示了每次不计算自动实现属性的表达式,与显式属性的 getter 方法一样。
警告
某些库(如 Entity Framework(System.Data.Entity)在基类构造函数中执行自定义作,这些函数不适用于自动实现的属性的初始化。 在这些情况下,请尝试使用显式属性。
属性可以是类、结构、区分联合、记录、接口和类型扩展的成员,也可以在对象表达式中定义。
属性可以应用于属性。 若要将属性应用于属性,请在属性之前在单独的行上写入该属性。 有关详细信息,请参阅 属性。
默认情况下,属性为公共属性。 辅助功能修饰符也可以应用于属性。 若要应用辅助功能修饰符,如果属性的名称应用于和getset方法,请立即将其添加到属性名称之前;如果每个访问器需要不同的辅助功能,请在和get关键字之前set添加它。
辅助功能修饰符可以是下列项之一:public、privateinternal、 。 有关详细信息,请参阅 访问控制。
每次访问属性时,都会执行属性实现。
静态和实例属性
属性可以是静态属性或实例属性。 可以在不使用实例的情况下调用静态属性,并用于与类型(而不是单个对象)关联的值。 对于静态属性,请省略自标识符。 实例属性需要自标识符。
以下静态属性定义基于一种场景,在该方案中,你有一个静态字段,该字段 myStaticValue 是该属性的后盾存储区。
static member MyStaticProperty
with get() = myStaticValue
and set(value) = myStaticValue <- value
属性也可以类似于数组,在这种情况下,它们称为 索引属性。 有关详细信息,请参阅 索引属性。
属性的类型批注
在许多情况下,编译器有足够的信息来推断后盾存储类型的属性类型,但可以通过添加类型注释来显式设置类型。
// 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 访问器 <- 的属性。
// 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 只是意味着存在与属性关联的虚拟调度。 抽象属性可以真正抽象,即在同一类中没有定义。 因此,包含此类属性的类是抽象类。 或者,抽象可能只是意味着属性是虚拟的,在这种情况下,定义必须存在于同一类中。 请注意,抽象属性不能是私有的,如果一个访问器是抽象的,另一个属性也必须是抽象的。 有关抽象类的详细信息,请参阅 抽象类。
// 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