Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se describe cómo definir y usar constructores para crear e inicializar objetos de clase y estructura.
Construcción de objetos de clase
Los objetos de tipos de clase tienen constructores. Hay dos tipos de constructores. Uno es el constructor principal, cuyos parámetros aparecen entre paréntesis justo después del nombre del tipo. Opcionalmente, puede especificar constructores adicionales mediante la new palabra clave . Cualquier constructor adicional de este tipo debe llamar al constructor principal.
El constructor principal contiene let enlaces y do que aparecen al principio de la definición de clase. Un let enlace declara campos privados y métodos de la clase; un do enlace ejecuta código. Para obtener más información sobre let los enlaces en constructores de clases, vea let Enlaces en clases. Para obtener más información sobre do los enlaces en constructores, vea do Enlaces en clases.
Independientemente de si el constructor al que desea llamar es un constructor principal o un constructor adicional, puede crear objetos mediante una new expresión, con o sin la palabra clave opcional new . Inicializa los objetos junto con argumentos de constructor, ya sea enumerando los argumentos en orden y separados por comas y entre paréntesis, o usando argumentos y valores con nombre entre paréntesis. También puede establecer propiedades en un objeto durante la construcción del objeto mediante los nombres de propiedad y la asignación de valores al igual que se usan argumentos de constructor con nombre.
En el código siguiente se muestra una clase que tiene un constructor y varias formas de crear objetos:
// This class has a primary constructor that takes three arguments
// and an additional constructor that calls the primary constructor.
type MyClass(x0, y0, z0) =
let mutable x = x0
let mutable y = y0
let mutable z = z0
do
printfn "Initialized object that has coordinates (%d, %d, %d)" x y z
member this.X with get() = x and set(value) = x <- value
member this.Y with get() = y and set(value) = y <- value
member this.Z with get() = z and set(value) = z <- value
new() = MyClass(0, 0, 0)
// Create by using the new keyword.
let myObject1 = new MyClass(1, 2, 3)
// Create without using the new keyword.
let myObject2 = MyClass(4, 5, 6)
// Create by using named arguments.
let myObject3 = MyClass(x0 = 7, y0 = 8, z0 = 9)
// Create by using the additional constructor.
let myObject4 = MyClass()
La salida es la siguiente:
Initialized object that has coordinates (1, 2, 3)
Initialized object that has coordinates (4, 5, 6)
Initialized object that has coordinates (7, 8, 9)
Initialized object that has coordinates (0, 0, 0)
Construcción de estructuras
Las estructuras siguen todas las reglas de las clases. Por lo tanto, puede tener un constructor principal y puede proporcionar constructores adicionales mediante new. Sin embargo, hay una diferencia importante entre las estructuras y las clases: las estructuras pueden tener un constructor sin parámetros (es decir, uno sin argumentos) incluso si no se define ningún constructor principal. El constructor sin parámetros inicializa todos los campos en el valor predeterminado de ese tipo, normalmente cero o su equivalente. Los constructores que defina para las estructuras deben tener al menos un argumento para que no entren en conflicto con el constructor sin parámetros.
Además, las estructuras suelen tener campos creados mediante la val palabra clave ; las clases también pueden tener estos campos. Las estructuras y clases que tienen campos definidos mediante la val palabra clave también se pueden inicializar en constructores adicionales mediante expresiones de registro, como se muestra en el código siguiente.
type MyStruct =
struct
val X : int
val Y : int
val Z : int
new(x, y, z) = { X = x; Y = y; Z = z }
end
let myStructure1 = new MyStruct(1, 2, 3)
Para obtener más información, vea Campos explícitos: la val palabra clave .
Ejecución de efectos secundarios en constructores
Un constructor principal de una clase puede ejecutar código en un do enlace. Sin embargo, ¿qué ocurre si tiene que ejecutar código en un constructor adicional, sin un do enlace? Para ello, use la then palabra clave .
// Executing side effects in the primary constructor and
// additional constructors.
type Person(nameIn : string, idIn : int) =
let mutable name = nameIn
let mutable id = idIn
do printfn "Created a person object."
member this.Name with get() = name and set(v) = name <- v
member this.ID with get() = id and set(v) = id <- v
new() =
Person("Invalid Name", -1)
then
printfn "Created an invalid person object."
let person1 = new Person("Humberto Acevedo", 123458734)
let person2 = new Person()
Los efectos secundarios del constructor principal se siguen ejecutando. Por lo tanto, la salida es la siguiente:
Created a person object.
Created a person object.
Created an invalid person object.
La razón por la then que es necesaria en lugar de otra do es que la do palabra clave tiene su significado estándar de delimitar una unitexpresión que devuelve cuando está presente en el cuerpo de un constructor adicional. Solo tiene un significado especial en el contexto de los constructores principales.
Identificadores independientes en constructores
En otros miembros, se proporciona un nombre para el objeto actual en la definición de cada miembro. También puede colocar el identificador propio en la primera línea de la definición de clase mediante la as palabra clave inmediatamente después de los parámetros del constructor. En el ejemplo siguiente se muestra esta sintaxis.
type MyClass1(x) as this =
// This use of the self identifier produces a warning - avoid.
let x1 = this.X
// This use of the self identifier is acceptable.
do printfn "Initializing object with X =%d" this.X
member this.X = x
En constructores adicionales, también puede definir un identificador propio colocando la as cláusula justo después de los parámetros del constructor. En el ejemplo siguiente se muestra esta sintaxis:
type MyClass2(x : int) =
member this.X = x
new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X
Los problemas pueden producirse al intentar usar un objeto antes de que se defina por completo. Por lo tanto, los usos del identificador propio pueden hacer que el compilador emita una advertencia e inserte comprobaciones adicionales para asegurarse de que no se tiene acceso a los miembros de un objeto antes de inicializar el objeto. Solo debe usar el identificador propio en los do enlaces del constructor principal o después de la then palabra clave en constructores adicionales.
El nombre del identificador propio no tiene que ser this. Puede ser cualquier identificador válido.
Asignación de valores a propiedades en la inicialización
Puede asignar valores a las propiedades de un objeto de clase en el código de inicialización anexando una lista de asignaciones del formulario property = value a la lista de argumentos de un constructor. Esto se muestra en el ejemplo de código siguiente:
type Account() =
let mutable balance = 0.0
let mutable number = 0
let mutable firstName = ""
let mutable lastName = ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(AccountNumber=8782108,
FirstName="Darren", LastName="Parker",
Balance=1543.33)
La siguiente versión del código anterior muestra la combinación de argumentos ordinarios, argumentos opcionales y valores de propiedad en una llamada de constructor:
type Account(accountNumber : int, ?first: string, ?last: string, ?bal : float) =
let mutable balance = defaultArg bal 0.0
let mutable number = accountNumber
let mutable firstName = defaultArg first ""
let mutable lastName = defaultArg last ""
member this.AccountNumber
with get() = number
and set(value) = number <- value
member this.FirstName
with get() = firstName
and set(value) = firstName <- value
member this.LastName
with get() = lastName
and set(value) = lastName <- value
member this.Balance
with get() = balance
and set(value) = balance <- value
member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount
let account1 = new Account(8782108, bal = 543.33,
FirstName="Raman", LastName="Iyer")
Constructores de la clase heredada
Al heredar de una clase base que tiene un constructor, debe especificar sus argumentos en la cláusula inherit. Para obtener más información, vea Constructores y herencia.
Constructores estáticos o constructores de tipo
Además de especificar código para crear objetos, los enlaces estáticos let y do se pueden crear en tipos de clase que se ejecutan antes de que el tipo se use por primera vez para realizar la inicialización en el nivel de tipo. Para obtener más información, vea let Enlaces en clases y do enlaces en clases.