Поделиться через


Явные поля. Ключевое слово 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 появляются вместе в определении типа, то это определение автоматически реализуемого свойства. Дополнительные сведения см. в разделе Свойства.

См. также