Konstruktory

Tento článek popisuje, jak definovat a používat konstruktory k vytvoření a inicializaci objektů třídy a struktury.

Konstrukce objektů třídy

Objekty typů tříd mají konstruktory. Existují dva druhy konstruktorů. Jedním z nich je primární konstruktor, jehož parametry se zobrazují v závorkách těsně za názvem typu. Pomocí klíčového new slova určíte další volitelné konstruktory. Všechny takové další konstruktory musí volat primární konstruktor.

Primární konstruktor obsahuje let a do vazby, které se zobrazí na začátku definice třídy. Vazba let deklaruje privátní pole a metody třídy; do vazba spouští kód. Další informace o let vazbách v konstruktorech tříd naleznete v tématu let Vazby v třídách. Další informace o do vazbách v konstruktorech naleznete v tématu do Vazby v třídách.

Bez ohledu na to, zda je konstruktor, který chcete volat, primární konstruktor nebo další konstruktor, můžete vytvořit objekty pomocí výrazu new , s volitelným klíčovým slovem nebo bez tohoto klíčového new slova. Inicializujete objekty společně s argumenty konstruktoru, buď výpisem argumentů v pořadí a odděleny čárkami a uzavřenými v závorkách, nebo pomocí pojmenovaných argumentů a hodnot v závorkách. Vlastnosti objektu můžete také nastavit při vytváření objektu pomocí názvů vlastností a přiřazováním hodnot stejně jako používáte pojmenované argumenty konstruktoru.

Následující kód znázorňuje třídu, která má konstruktor a různé způsoby vytváření 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()

Výstup je následující:

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)

Konstrukce konstrukcí

Struktury se řídí všemi pravidly tříd. Proto můžete mít primární konstruktor a můžete poskytnout další konstruktory pomocí new. Existuje však jeden důležitý rozdíl mezi strukturami a třídami: struktury mohou mít konstruktor bez parametrů (tj. jeden bez argumentů), i když není definován žádný primární konstruktor. Konstruktor bez parametrů inicializuje všechna pole na výchozí hodnotu daného typu, obvykle nula nebo jeho ekvivalent. Všechny konstruktory, které definujete pro struktury, musí mít alespoň jeden argument, aby nebyly v konfliktu s konstruktorem bez parametrů.

Struktury také často obsahují pole vytvořená pomocí klíčového val slova; třídy mohou mít také tato pole. Struktury a třídy, které mají pole definovaná pomocí klíčového val slova, lze také inicializovat v dalších konstruktorech pomocí výrazů záznamů, jak je znázorněno v následujícím kódu.

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)

Další informace naleznete v tématu Explicitní pole: Klíčové val slovo.

Provádění vedlejších efektů v konstruktorech

Primární konstruktor ve třídě může spouštět kód ve vazbě do . Co když ale musíte spustit kód v dalším konstruktoru bez vazby do ? K tomu použijete then klíčové slovo.

 // 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()

Vedlejší účinky primárního konstruktoru se stále provádějí. Výstup je proto následující:

Created a person object.
Created a person object.
Created an invalid person object.

Důvodem, proč then je požadováno místo jiného do , je, že do klíčové slovo má svůj standardní význam oddělovače unit-returning výraz, pokud je přítomný v těle dalšího konstruktoru. Má pouze zvláštní význam v kontextu primárních konstruktorů.

Identifikátory sebe v konstruktorech

V ostatních členech zadáte název aktuálního objektu v definici každého člena. Identifikátor sebeobsadu můžete také umístit na první řádek definice třídy pomocí klíčového as slova bezprostředně za parametry konstruktoru. Následující příklad znázorňuje tuto syntaxi.

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

V dalších konstruktorech můžete také definovat identifikátor sebeobsady as tak, že klauzuli umístíte přímo za parametry konstruktoru. Následující příklad znázorňuje tuto syntaxi:

type MyClass2(x : int) =
    member this.X = x
    new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X

K problémům může dojít, když se pokusíte použít objekt dříve, než je plně definován. Proto použití vlastního identifikátoru může způsobit, že kompilátor vygeneruje upozornění a vloží další kontroly, aby se zajistilo, že členové objektu nebudou před inicializovánem objektu. V vazbách primárního konstruktoru nebo za then klíčovým slovem v dalších konstruktorech byste měli použít pouze identifikátor do sebe sama.

Název vlastního identifikátoru nemusí být this. Může to být libovolný platný identifikátor.

Přiřazení hodnot vlastnostem při inicializaci

Hodnoty můžete přiřadit vlastnostem objektu třídy v inicializačním kódu připojením seznamu přiřazení formuláře property = value do seznamu argumentů pro konstruktor. Toto je znázorněno v následujícím příkladu kódu:

 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)

Následující verze předchozího kódu znázorňuje kombinaci běžných argumentů, volitelných argumentů a nastavení vlastností v jednom volání konstruktoru:

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")

Konstruktory v zděděné třídě

Při dědění ze základní třídy, která má konstruktor, je nutné zadat jeho argumenty v zděděné klauzuli. Další informace naleznete v tématu Konstruktory a dědičnost.

Statické konstruktory nebo konstruktory typů

Kromě zadávání kódu pro vytváření objektů lze statické let a do vazby vytvářet v typech tříd, které se spouští před tím, než se typ poprvé použije k inicializaci na úrovni typu. Další informace naleznete v tématu let Vazby v třídách a do vazbách v třídách.

Viz také