Свойства (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

// 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

Для свойств чтения и записи, которые имеют get и метод, порядок get и setset может быть изменен. Кроме того, можно указать синтаксис, отображаемый только для get синтаксиса, а синтаксис, показанный set только вместо использования объединенного синтаксиса. Это упрощает комментировать отдельный get или set метод, если это может потребоваться. Эта альтернатива использованию объединенного синтаксиса показана в следующем коде.

member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value

Частные значения, которые содержат данные для свойств, вызывают резервные хранилища. Чтобы компилятор автоматически создавал резервное хранилище, используйте ключевое слово, member valопустите идентификатор самостоятельно, а затем укажите выражение для инициализации свойства. Если свойство должно быть изменяемым, включите with get, set. Например, следующий тип класса включает два автоматически реализованных свойства. Property1 доступен только для чтения и инициализируется аргументом, предоставленным основному конструктору, и является свойством settable, инициализируемым 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 не изменяется при повторном вызове, в то время как явное значениеProperty изменяется при каждом вызове. В этом примере показано, что выражение для автоматически реализованного свойства не вычисляется каждый раз, как метод getter для явного свойства.

Предупреждение

Существуют некоторые библиотеки, такие как Entity Framework (System.Data.Entity), которые выполняют пользовательские операции в конструкторах базовых классов, которые не работают хорошо с инициализацией автоматически реализованных свойств. В этих случаях попробуйте использовать явные свойства.

Свойства могут быть членами классов, структур, дискриминированных профсоюзов, записей, интерфейсов и расширений типов, а также могут быть определены в выражениях объектов.

Атрибуты можно применять к свойствам. Чтобы применить атрибут к свойству, напишите атрибут в отдельной строке перед свойством. Дополнительные сведения см. в разделе Атрибуты.

По умолчанию свойства являются общедоступными. Модификаторы специальных возможностей также можно применять к свойствам. Чтобы применить модификатор специальных возможностей, добавьте его непосредственно перед именем свойства, если оно предназначено для применения как к get методам, так и set к методам; добавьте его перед get и set ключевое слово, если для каждого метода доступа требуется разные специальные возможности. Модификатор специальных возможностей может быть одним из следующихpublic: , private. internal Дополнительные сведения см. в разделе Access Control.

Реализации свойств выполняются при каждом обращении к свойству.

Свойства статического и экземпляра

Свойства могут быть статическими или экземплярами. Статические свойства можно вызывать без экземпляра и использовать для значений, связанных с типом, а не с отдельными объектами. Для статических свойств опустите идентификатор самостоятельно. Для свойств экземпляра требуется идентификатор самостоятельного идентификатора.

Следующее определение статического свойства основано на сценарии, в котором имеется статическое поле 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

См. также