Constructors
In dit artikel wordt beschreven hoe u constructors definieert en gebruikt om klasse- en structuurobjecten te maken en te initialiseren.
Bouw van klasseobjecten
Objecten van klassetypen hebben constructors. Er zijn twee soorten constructors. Een is de primaire constructor, waarvan de parameters tussen haakjes worden weergegeven vlak na de typenaam. U geeft andere, optionele extra constructors op met behulp van het new
trefwoord. Dergelijke extra constructors moeten de primaire constructor aanroepen.
De primaire constructor bevat let
en do
bindingen die aan het begin van de klassedefinitie worden weergegeven. Een let
binding declareert privévelden en -methoden van de klasse; een do
binding voert code uit. Zie Bindingen in klassen voor meer informatie over let
bindingen in klasseconstructorslet
. Zie Bindingen in klassen voor meer informatie over do
bindingen in constructorsdo
.
Ongeacht of de constructor die u wilt aanroepen een primaire constructor of een extra constructor is, kunt u objecten maken met behulp van een new
expressie, met of zonder het optionele new
trefwoord. U initialiseert uw objecten samen met constructorargumenten door de argumenten in volgorde weer te geven en gescheiden door komma's en tussen haakjes te plaatsen, of door benoemde argumenten en waarden tussen haakjes te gebruiken. U kunt ook eigenschappen instellen voor een object tijdens de constructie van het object door de eigenschapsnamen te gebruiken en waarden toe te wijzen, net zoals u benoemde constructorargumenten gebruikt.
De volgende code illustreert een klasse met een constructor en verschillende manieren om objecten te maken:
// 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()
De uitvoer is als volgt:
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)
Bouw van structuren
Structuren volgen alle regels van klassen. Daarom kunt u een primaire constructor hebben en u kunt aanvullende constructors opgeven met behulp van new
. Er is echter een belangrijk verschil tussen structuren en klassen: structuren kunnen een parameterloze constructor (dat wil gezegd, één zonder argumenten) hebben, zelfs als er geen primaire constructor is gedefinieerd. De constructor zonder parameter initialiseert alle velden naar de standaardwaarde voor dat type, meestal nul of het equivalent ervan. Constructors die u voor structuren definieert, moeten ten minste één argument hebben, zodat ze niet conflicteren met de parameterloze constructor.
Structuren bevatten vaak velden die zijn gemaakt met behulp van het val
trefwoord; klassen kunnen deze velden ook hebben. Structuren en klassen met velden die zijn gedefinieerd met behulp van het val
trefwoord, kunnen ook worden geïnitialiseerd in extra constructors met behulp van recordexpressies, zoals wordt weergegeven in de volgende code.
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)
Zie Expliciete velden: Het val
trefwoord voor meer informatie.
Neveneffecten uitvoeren in constructors
Een primaire constructor in een klasse kan code in een do
binding uitvoeren. Wat moet u echter doen als u code moet uitvoeren in een extra constructor, zonder een do
binding? Hiervoor gebruikt u het then
trefwoord.
// 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()
De bijwerkingen van de primaire constructor worden nog steeds uitgevoerd. Daarom is de uitvoer als volgt:
Created a person object.
Created a person object.
Created an invalid person object.
De reden waarom then
is vereist in plaats van een andere do
is dat het do
trefwoord de standaard betekenis heeft van het scheiden van een unit
-retourexpressie wanneer deze aanwezig is in de hoofdtekst van een extra constructor. Het heeft alleen speciale betekenis in de context van primaire constructors.
Zelf-id's in constructors
In andere leden geeft u een naam op voor het huidige object in de definitie van elk lid. U kunt de self-id ook op de eerste regel van de klassedefinitie plaatsen met behulp van het as
trefwoord direct na de constructorparameters. In het volgende voorbeeld ziet u deze syntaxis.
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
In aanvullende constructors kunt u ook een self-id definiëren door de as
component direct na de constructorparameters te plaatsen. In het volgende voorbeeld ziet u deze syntaxis:
type MyClass2(x : int) =
member this.X = x
new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X
Er kunnen problemen optreden wanneer u een object probeert te gebruiken voordat het volledig is gedefinieerd. Daarom kan het gebruik van de self-id ertoe leiden dat de compiler een waarschuwing verzendt en extra controles invoegt om ervoor te zorgen dat de leden van een object niet worden geopend voordat het object wordt geïnitialiseerd. Gebruik alleen de self-id in de do
bindingen van de primaire constructor of na het then
trefwoord in extra constructors.
De naam van de self-id hoeft niet te zijn this
. Dit kan elke geldige id zijn.
Waarden toewijzen aan eigenschappen bij initialisatie
U kunt waarden toewijzen aan de eigenschappen van een klasseobject in de initialisatiecode door een lijst met toewijzingen van het formulier property = value
toe te voegen aan de lijst met argumenten voor een constructor. Dit wordt weergegeven in het volgende codevoorbeeld:
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)
De volgende versie van de vorige code illustreert de combinatie van gewone argumenten, optionele argumenten en eigenschapsinstellingen in één constructor-aanroep:
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")
Constructors in overgenomen klasse
Wanneer u een basisklasse overneemt die een constructor heeft, moet u de argumenten opgeven in de component overname. Zie Constructors en overname voor meer informatie.
Statische constructors of typeconstructors
Naast het opgeven van code voor het maken van objecten, kunnen statische let
en do
bindingen worden gemaakt in klassetypen die worden uitgevoerd voordat het type voor het eerst wordt gebruikt om initialisatie uit te voeren op typeniveau. Zie let
Bindingen in klassen en do
bindingen in klassen voor meer informatie.