Campos explícitos: palabra clave val
La palabra clave val
se usa para declarar una ubicación para almacenar un valor en un tipo de clase o estructura sin inicializarlo. Las ubicaciones de almacenamiento que se declaran de esta manera se conocen como campos explícitos. Otro uso de la val
palabra clave está junto con la member
palabra clave para declarar una propiedad implementada automáticamente. Para obtener más información sobre las propiedades implementadas automáticamente, vea Propiedades.
Sintaxis
val [ mutable ] [ access-modifier ] field-name : type-name
Comentarios
La forma más habitual de definir campos en un tipo de clase o estructura es usar un enlace let
. Sin embargo, los enlaces let
deben inicializarse como parte del constructor de clase, lo que no siempre es posible, necesario o deseable. Puede usar la palabra clave val
cuando quiera un campo que no se haya inicializado.
Los campos explícitos pueden ser estáticos o no estáticos. El modificador de acceso puede ser public
, private
o internal
. De forma predeterminada, los campos explícitos son públicos. Esto difiere de los enlaces let
de las clases, que siempre son privados.
El atributo DefaultValue es necesario en los campos explícitos de los tipos de clase que tienen un constructor primario. Este atributo especifica que el campo se inicializa en cero. El tipo del campo debe admitir la inicialización en cero. Los tipos que admiten la inicialización en cero son los siguientes:
- Un tipo primitivo que tenga un valor de cero.
- Un tipo que admita un valor nulo, ya sea como valor normal, como valor anormal o como representación de un valor. Esto incluye clases, tuplas, registros, funciones, interfaces, tipos de referencia .NET, el tipo
unit
y tipos de unión discriminada. - Un tipo de valor. NET.
- Una estructura cuyos campos admitan el valor cero predeterminado.
Por ejemplo, un campo inmutable denominado someField
tiene un campo de respaldo en la representación compilada de .NET con el nombre someField@
y el usuario accede al valor almacenado con una propiedad denominada someField
.
Para un campo mutable, la representación compilada de .NET es un campo .NET.
Advertencia
El espacio de nombres System.ComponentModel
de .NET Framework contiene un atributo que tiene el mismo nombre. Para obtener más información sobre el atributo, vea DefaultValueAttribute.
El código siguiente muestra el uso de campos explícitos y, para la comparación, un let
de enlace en una clase que tiene un constructor primario. Tenga en cuenta que el campo enlazado a let
myInt1
es privado. Si se hace referencia al campo enlazado a let
myInt1
desde un método de miembro, el identificador propio this
no es necesario. Pero si hace referencia a los campos explícitos myInt2
y myString
, se requiere el identificador propio.
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)
La salida es como sigue:
11 12 abc
30 def
En el código siguiente se muestra el uso de campos explícitos en una clase que no tiene constructor primario. En este caso, el atributo DefaultValue
no es necesario, pero todos los campos deben estar inicializados en los constructores definidos para el tipo.
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)
La salida es 35 22
.
En el código siguiente se muestra el uso de campos explícitos en una estructura. Como una estructura es un tipo de valor, automáticamente tiene un constructor sin parámetros que establece los valores de sus campos en cero. Por lo tanto, el atributo DefaultValue
no es necesario.
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)
La salida es 11 xyz
.
Tenga en cuenta que, si va a inicializar la estructura con campos mutable
sin palabra clave mutable
, las asignaciones funcionarán en una copia de la estructura que se descartará justo después de la asignación. Por lo tanto, la estructura no cambiará.
[<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
Los campos explícitos no están pensados para un uso rutinario. En general, siempre que sea posible debe usar un enlace let
en una clase en lugar de un campo explícito. Los campos explícitos son útiles en determinados escenarios de interoperabilidad, como cuando se necesita definir una estructura que se usará en una llamada de invocación a una plataforma API nativa o en escenarios de interoperabilidad COM. Para obtener más información, vea Funciones externas. Otra situación en la que podría ser necesario un campo explícito es cuando se trabaja con un generador de código F # que emite clases sin un constructor primario. Los campos explícitos también son útiles para las variables de subproceso estático o construcciones similares. Para más información, consulte System.ThreadStaticAttribute
.
Cuando las palabras clave member val
aparecen juntas en una definición de tipo, se trata de la definición de una propiedad implementada automáticamente. Para obtener más información, consulta Propiedades.
Consulte también
- Propiedades
- Miembros
let
Bindings in Classes (Enlaceslet
en clases)