Share via


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.

Zie ook