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.