Konstruktorer
Den här artikeln beskriver hur du definierar och använder konstruktorer för att skapa och initiera klass- och strukturobjekt.
Konstruktion av klassobjekt
Objekt av klasstyper har konstruktorer. Det finns två typer av konstruktorer. Den ena är den primära konstruktorn, vars parametrar visas inom parenteser strax efter typnamnet. Du anger andra valfria ytterligare konstruktorer med hjälp av nyckelordet new
. Alla sådana ytterligare konstruktorer måste anropa den primära konstruktorn.
Den primära konstruktorn innehåller let
och do
bindningar som visas i början av klassdefinitionen. En let
bindning deklarerar privata fält och metoder för klassen. En do
bindning kör kod. Mer information om let
bindningar i klasskonstruktorer finns let
i Bindningar i klasser. Mer information om do
bindningar i konstruktorer do
finns i Bindningar i klasser.
Oavsett om konstruktorn som du vill anropa är en primär konstruktor eller en ytterligare konstruktor kan du skapa objekt med ett new
uttryck, med eller utan det valfria new
nyckelordet. Du initierar dina objekt tillsammans med konstruktorargument, antingen genom att visa argumenten i ordning och avgränsade med kommatecken och omges av parenteser, eller genom att använda namngivna argument och värden inom parenteser. Du kan också ange egenskaper för ett objekt under konstruktionen av objektet genom att använda egenskapsnamnen och tilldela värden precis som du använder namngivna konstruktorargument.
Följande kod illustrerar en klass som har en konstruktor och olika sätt att skapa objekt:
// 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()
Utdata är följande:
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)
Konstruktion av strukturer
Strukturer följer alla klassers regler. Därför kan du ha en primär konstruktor och du kan tillhandahålla ytterligare konstruktorer med hjälp new
av . Det finns dock en viktig skillnad mellan strukturer och klasser: strukturer kan ha en parameterlös konstruktor (dvs. en utan argument) även om ingen primär konstruktor har definierats. Den parameterlösa konstruktorn initierar alla fält till standardvärdet för den typen, vanligtvis noll eller motsvarande. Alla konstruktorer som du definierar för strukturer måste ha minst ett argument så att de inte står i konflikt med den parameterlösa konstruktorn.
Strukturer har också ofta fält som skapas med hjälp av nyckelordet val
. Klasserna kan också ha dessa fält. Strukturer och klasser som har fält som definierats med hjälp av nyckelordet val
kan också initieras i ytterligare konstruktorer med hjälp av postuttryck, som visas i följande kod.
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)
Mer information finns i Explicita fält: Nyckelordetval
.
Köra biverkningar i konstruktorer
En primär konstruktor i en klass kan köra kod i en do
bindning. Men vad händer om du måste köra kod i en ytterligare konstruktor, utan en do
bindning? För att göra detta använder du nyckelordet then
.
// 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()
Biverkningarna av den primära konstruktorn körs fortfarande. Därför är utdata följande:
Created a person object.
Created a person object.
Created an invalid person object.
Anledningen till varför then
krävs i stället för en annan do
är att nyckelordet do
har sin standard innebörd att avgränsa ett unit
-returning-uttryck när det finns i brödtexten i en ytterligare konstruktor. Den har bara särskild betydelse i samband med primära konstruktorer.
Självidentifierare i konstruktorer
I andra medlemmar anger du ett namn för det aktuella objektet i definitionen av varje medlem. Du kan också placera självidentifieraren på den första raden i klassdefinitionen med hjälp av nyckelordet as
omedelbart efter konstruktorparametrarna. I följande exempel visas den här syntaxen.
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
I ytterligare konstruktorer kan du också definiera en självidentifierare genom att placera as
satsen direkt efter konstruktorparametrarna. Följande exempel illustrerar den här syntaxen:
type MyClass2(x : int) =
member this.X = x
new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X
Problem kan uppstå när du försöker använda ett objekt innan det är helt definierat. Därför kan användning av självidentifieraren leda till att kompilatorn skickar en varning och infoga ytterligare kontroller för att säkerställa att medlemmarna i ett objekt inte nås innan objektet initieras. Du bör bara använda självidentifieraren i bindningarna för do
den primära konstruktorn eller efter nyckelordet then
i ytterligare konstruktorer.
Namnet på självidentifieraren behöver inte vara this
. Det kan vara vilken giltig identifierare som helst.
Tilldela värden till egenskaper vid initiering
Du kan tilldela värden till egenskaperna för ett klassobjekt i initieringskoden genom att lägga till en lista över tilldelningar av formuläret property = value
i argumentlistan för en konstruktor. Detta visas i följande kodexempel:
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)
Följande version av den föregående koden illustrerar kombinationen av vanliga argument, valfria argument och egenskapsinställningar i ett konstruktoranrop:
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")
Konstruktorer i ärvd klass
När du ärver från en basklass som har en konstruktor måste du ange dess argument i ärv-satsen. Mer information finns i Konstruktorer och arv.
Statiska konstruktorer eller typkonstruktorer
Förutom att ange kod för att skapa objekt kan statiska let
och do
bindningar redigeras i klasstyper som körs innan typen först används för att utföra initiering på typnivå. Mer information let
finns i Bindningar i klasser och do
bindningar i klasser.