Udostępnij za pośrednictwem


Konstruktory

W tym artykule opisano sposób definiowania i używania konstruktorów do tworzenia i inicjowania obiektów klasy i struktury.

Konstruowanie obiektów klasy

Obiekty typów klas mają konstruktory. Istnieją dwa rodzaje konstruktorów. Jednym z nich jest podstawowy konstruktor, którego parametry pojawiają się w nawiasach tuż po nazwie typu. Można określić inne, opcjonalne dodatkowe konstruktory przy użyciu słowa kluczowego new . Każdy taki dodatkowy konstruktor musi wywołać konstruktor podstawowy.

Podstawowy konstruktor zawiera let powiązania, do które pojawiają się na początku definicji klasy. let Powiązanie deklaruje prywatne pola i metody klasy; do powiązanie wykonuje kod. Aby uzyskać więcej informacji na temat let powiązań w konstruktorach klas, zobacz let Powiązania w klasach. Aby uzyskać więcej informacji na temat do powiązań w konstruktorach, zobacz do Powiązania w klasach.

Niezależnie od tego, czy konstruktor, który chcesz wywołać, jest konstruktorem podstawowym, czy dodatkowym konstruktorem, można utworzyć obiekty przy użyciu new wyrażenia z opcjonalnym słowem kluczowym lub bez tego.new Zainicjuj obiekty razem z argumentami konstruktora, wymieniając argumenty w kolejności i rozdzielając przecinkami i ujęte w nawiasy albo używając nazwanych argumentów i wartości w nawiasach. Właściwości obiektu można również ustawić podczas konstruowania obiektu przy użyciu nazw właściwości i przypisywać wartości tak samo jak argumenty konstruktora nazwanego.

Poniższy kod ilustruje klasę, która ma konstruktor i różne sposoby tworzenia obiektów:

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

Wynik jest następujący:

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)

Budowa konstrukcji

Struktury są zgodne ze wszystkimi regułami klas. W związku z tym można mieć konstruktor podstawowy i można udostępnić dodatkowe konstruktory przy użyciu polecenia new. Istnieje jednak jedna ważna różnica między strukturami i klasami: struktury mogą mieć konstruktor bez parametrów (czyli jeden bez argumentów), nawet jeśli nie zdefiniowano żadnego konstruktora podstawowego. Konstruktor bez parametrów inicjuje wszystkie pola do wartości domyślnej dla tego typu, zwykle zero lub jego odpowiednik. Wszystkie konstruktory zdefiniowane dla struktur muszą mieć co najmniej jeden argument, aby nie powodować konfliktu z konstruktorem bez parametrów.

Ponadto struktury często mają pola tworzone przy użyciu słowa kluczowego val ; klasy mogą również mieć te pola. Struktury i klasy, które mają pola zdefiniowane przy użyciu słowa kluczowego val , można również zainicjować w dodatkowych konstruktorach przy użyciu wyrażeń rekordów, jak pokazano w poniższym kodzie.

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)

Aby uzyskać więcej informacji, zobacz Jawne pola: val Słowo kluczowe.

Wykonywanie efektów ubocznych w konstruktorach

Konstruktor podstawowy w klasie może wykonywać kod w powiązaniu do . Co jednak zrobić, jeśli trzeba wykonać kod w dodatkowym konstruktorze do bez powiązania? W tym celu należy użyć słowa kluczowego 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()

Skutki uboczne podstawowego konstruktora nadal są wykonywane. W związku z tym dane wyjściowe są następujące:

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

Powodem, dla którego then jest wymagana zamiast innego do , jest to, że do słowo kluczowe ma standardowe znaczenie ogranicznika unit-zwracanego wyrażenia, gdy znajduje się w treści dodatkowego konstruktora. Ma on specjalne znaczenie tylko w kontekście konstruktorów podstawowych.

Identyfikatory własne w konstruktorach

W innych elementach członkowskich należy podać nazwę bieżącego obiektu w definicji każdego elementu członkowskiego. Można również umieścić identyfikator własny w pierwszym wierszu definicji klasy, używając as słowa kluczowego bezpośrednio zgodnie z parametrami konstruktora. Poniższy przykład ilustruje tę składnię.

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

W dodatkowych konstruktorach można również zdefiniować identyfikator własny, umieszczając klauzulę as bezpośrednio po parametrach konstruktora. Poniższy przykład ilustruje tę składnię:

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

Problemy mogą wystąpić, gdy próbujesz użyć obiektu, zanim zostanie on w pełni zdefiniowany. W związku z tym użycie identyfikatora własnego może spowodować, że kompilator emituje ostrzeżenie i wstawia dodatkowe kontrole, aby upewnić się, że elementy członkowskie obiektu nie są dostępne przed zainicjowaniem obiektu. Należy użyć tylko identyfikatora własnego w do powiązaniach konstruktora podstawowego lub po słowie then kluczowym w dodatkowych konstruktorach.

Nazwa identyfikatora samodzielnego nie musi być .this Może to być dowolny prawidłowy identyfikator.

Przypisywanie wartości do właściwości podczas inicjowania

Wartości można przypisać do właściwości obiektu klasy w kodzie inicjowania, dołączając listę przypisań formularza property = value do listy argumentów konstruktora. Jest to pokazane w poniższym przykładzie kodu:

 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)

Poniższa wersja poprzedniego kodu ilustruje kombinację zwykłych argumentów, opcjonalnych argumentów i ustawień właściwości w jednym wywołaniu konstruktora:

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 w klasie dziedziczonej

Podczas dziedziczenia z klasy bazowej, która ma konstruktor, należy określić jego argumenty w klauzuli dziedziczonej. Aby uzyskać więcej informacji, zobacz Konstruktory i dziedziczenie.

Konstruktory statyczne lub konstruktory typów

Oprócz określania kodu do tworzenia obiektów, statyczne let i do powiązania można tworzyć w typach klas wykonywanych przed pierwszym zastosowaniem typu do wykonywania inicjowania na poziomie typu. Aby uzyskać więcej informacji, zobacz let Powiązania w klasach i do powiązaniach w klasach.

Zobacz też