Явные поля. Ключевое слово val
Ключевое слово val
используется для объявления расположения для сохранения значения в типе класса или структуры без его инициализации. Расположения хранилища, объявленные таким образом, называются явными полями. Другое использование ключевого слова состоит в сочетании val
с member
ключевым словом для объявления автоматически реализованного свойства. Дополнительные сведения о автоматически реализованных свойствах см. в разделе "Свойства".
Синтаксис
val [ mutable ] [ access-modifier ] field-name : type-name
Замечания
Обычно поля в типе класса или структуры задаются с помощью привязки let
. Однако привязки let
должны инициализироваться как часть конструктора класса, что не всегда возможно, необходимо или желательно. Если требуется неинициализированное поле, можно использовать ключевое слово val
.
Явные поля могут быть статическими или не статическими. Модификатор доступа может быть public
, private
или internal
. По умолчанию явные поля являются открытыми. Это отличается от привязок let
в классах, которые всегда являются закрытыми.
Атрибут DefaultValue необходим для явных полей в типах классов, имеющих основной конструктор. Этот атрибут указывает, что поле инициализируется нулевым значением. Тип поля должен поддерживать инициализацию нулем. Тип поддерживает инициализацию нулем, если он является одним из следующих типов.
- Тип-примитив, который имеет нулевое значение.
- Тип, поддерживающий значение null как нормальное значение, как аномальное значение или как представление значения. Сюда входят классы, кортежи, записи, функции, интерфейсы, ссылочные типы .NET, тип
unit
и типы размеченного объединения. - Тип значения .NET.
- Структура, все поля которой поддерживают нулевое значение по умолчанию.
Например, неизменяемое поле с именем someField
имеет резервное поле в скомпилированном в .NET представлении с именем someField@
, и вы обращаетесь к хранимому значению, используя свойство с именем someField
.
Для изменяемого поля скомпилированное в .NET представление является полем .NET.
Предупреждение
Пространство имен System.ComponentModel
платформа .NET Framework содержит атрибут, имеющий то же имя. Сведения об этом атрибуте см. в разделе DefaultValueAttribute.
В следующем коде показано использование явных полей и для сравнения привязки let
в классе, имеющем первичный конструктор. Обратите внимание, что привязанное с помощью let
поле myInt1
является закрытым. Если на привязанное с помощью let
поле myInt1
существует ссылка из метода-члена, идентификатор самого поля this
не требуется. Но если вы обращаетесь к явным полям myInt2
и myString
, идентификатор самого поля обязателен.
type MyType() =
let mutable myInt1 = 10
[<DefaultValue>] val mutable myInt2 : int
[<DefaultValue>] val mutable myString : string
member this.SetValsAndPrint( i: int, str: string) =
myInt1 <- i
this.myInt2 <- i + 1
this.myString <- str
printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)
let myObject = new MyType()
myObject.SetValsAndPrint(11, "abc")
// The following line is not allowed because let bindings are private.
// myObject.myInt1 <- 20
myObject.myInt2 <- 30
myObject.myString <- "def"
printfn "%d %s" (myObject.myInt2) (myObject.myString)
Вывод выглядит следующим образом.
11 12 abc
30 def
В следующем коде показывается использование явных полей в классе, в котором нет первичного конструктора. В этом случае атрибут DefaultValue
не требуется, но все поля должны быть инициализированы в конструкторах, определенных для типа.
type MyClass =
val a : int
val b : int
// The following version of the constructor is an error
// because b is not initialized.
// new (a0, b0) = { a = a0; }
// The following version is acceptable because all fields are initialized.
new(a0, b0) = { a = a0; b = b0; }
let myClassObj = new MyClass(35, 22)
printfn "%d %d" (myClassObj.a) (myClassObj.b)
Результат выглядит так: 35 22
.
В следующем коде демонстрируется использование явных полей в структуре. Так как структура является типом значения, он автоматически имеет конструктор без параметров, который задает значения его полей равным нулю. Таким образом, атрибут DefaultValue
не является обязательным.
type MyStruct =
struct
val mutable myInt : int
val mutable myString : string
end
let mutable myStructObj = new MyStruct()
myStructObj.myInt <- 11
myStructObj.myString <- "xyz"
printfn "%d %s" (myStructObj.myInt) (myStructObj.myString)
Результат выглядит так: 11 xyz
.
Если вы собираетесь инициализировать структуру с полями mutable
без mutable
ключевого слова, ваши назначения будут работать с копией структуры, которая будет удалена сразу после назначения. Поэтому структура не изменится.
[<Struct>]
type Foo =
val mutable bar: string
member self.ChangeBar bar = self.bar <- bar
new (bar) = {bar = bar}
let foo = Foo "1"
foo.ChangeBar "2" //make implicit copy of Foo, changes the copy, discards the copy, foo remains unchanged
printfn "%s" foo.bar //prints 1
let mutable foo' = Foo "1"
foo'.ChangeBar "2" //changes foo'
printfn "%s" foo'.bar //prints 2
Явные поля не предназначены для обычного использования. Как правило, по возможности следует использовать привязку let
в классе вместо явного поля. Явные поля удобны в некоторых сценариях взаимодействия, например если необходимо определить структуру, которая будет использоваться в вызове платформой собственного API или в сценариях COM-взаимодействия. Дополнительные сведения см. в разделе "Внешние функции". Кроме того, явное поле может потребоваться при работе с генератором кода F#, который порождает классы без первичного конструктора. Явные поля также полезны для потокостатических переменных или подобных конструкций. Дополнительные сведения см. в разделе System.ThreadStaticAttribute
.
Если ключевые слова member val
появляются вместе в определении типа, то это определение автоматически реализуемого свойства. Дополнительные сведения см. в разделе Свойства.