Constructeurs
Cet article décrit comment définir et utiliser des constructeurs pour créer et initialiser des objets de classe et de structure.
Construction d’objets de classe
Les objets de types de classe ont des constructeurs. Il existe deux sortes de constructeurs. Le premier est le constructeur principal, dont les paramètres apparaissent entre parenthèses juste après le nom du type. Vous spécifiez d’autres constructeurs supplémentaires facultatifs à l’aide du mot clé new
. Ces constructeurs supplémentaires doivent appeler le constructeur principal.
Le constructeur principal contient des liaisons let
et do
qui apparaissent au début de la définition de classe. Une liaison let
déclare des champs privés et des méthodes de la classe, une liaison do
exécute du code. Pour plus d’informations sur les liaisons let
dans les constructeurs de classe, consultez Liaisons let
dans les classes. Pour plus d’informations sur les liaisons do
dans les constructeurs de classe, consultez Liaisons do
dans les classes.
Que le constructeur que vous souhaitez appeler soit un constructeur principal ou un constructeur supplémentaire, vous pouvez créer des objets à l’aide d’une expression new
, avec ou sans le mot clé new
facultatif. Vous initialisez vos objets avec des arguments de constructeur, soit en répertoriant les arguments dans l’ordre et séparés par des virgules et placés entre parenthèses, soit en utilisant des arguments nommés et des valeurs entre parenthèses. Vous pouvez également définir des propriétés sur un objet pendant la construction de l’objet en utilisant les noms de propriété et en affectant des valeurs tout comme vous utilisez des arguments de constructeur nommé.
Le code suivant illustre une classe qui a un constructeur et différentes façons de créer des objets :
// 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()
La sortie se présente comme suit :
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)
Construction de structures
Les structures suivent toutes les règles des classes. Par conséquent, vous pouvez avoir un constructeur principal et vous pouvez fournir des constructeurs supplémentaires à l’aide de new
. Toutefois, il existe une différence importante entre les structures et les classes : les structures peuvent avoir un constructeur sans paramètre (c’est-à-dire sans arguments) même si aucun constructeur principal n’est défini. Le constructeur sans paramètre initialise tous les champs à la valeur par défaut de ce type, généralement zéro ou son équivalent. Tous les constructeurs que vous définissez pour les structures doivent avoir au moins un argument afin qu’ils n’entrent pas en conflit avec le constructeur sans paramètre.
En outre, les structures ont souvent des champs qui sont créés à l’aide du mot clé val
, les classes peuvent également avoir ces champs. Les structures et les classes qui ont des champs définis à l’aide du mot clé val
peuvent également être initialisées dans des constructeurs supplémentaires à l’aide d’expressions d’enregistrement, comme indiqué dans le code suivant.
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)
Pour plus d’informations, consultez Champs explicites : mot clé val
.
Exécution d’effets secondaires dans les constructeurs
Un constructeur principal d’une classe peut exécuter du code dans une liaison do
. Toutefois, que se passe-t-il si vous devez exécuter du code dans un constructeur supplémentaire, sans liaison do
? Pour ce faire, utilisez le mot clé 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()
Les effets secondaires du constructeur principal s’exécutent toujours. La sortie est donc la suivante :
Created a person object.
Created a person object.
Created an invalid person object.
La raison pour laquelle then
est obligatoire au lieu d’un autre do
est que le mot clé do
a sa signification standard de limiter une expression unit
-returning lorsqu’elle est présente dans le corps d’un constructeur supplémentaire. Il a uniquement une signification particulière dans le contexte des constructeurs principaux.
Auto-identificateurs dans les constructeurs
Dans les autres membres, vous fournissez un nom pour l’objet actuel dans la définition de chaque membre. Vous pouvez également placer l’auto-identificateur sur la première ligne de la définition de classe à l’aide du mot clé as
immédiatement après les paramètres du constructeur. L’exemple de code suivant illustre cette syntaxe.
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
Dans d’autres constructeurs, vous pouvez également définir un auto-identificateur en plaçant la clause as
juste après les paramètres du constructeur. L’exemple de code suivant illustre cette syntaxe :
type MyClass2(x : int) =
member this.X = x
new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X
Des problèmes peuvent survenir lorsque vous essayez d’utiliser un objet avant qu’il ne soit entièrement défini. Par conséquent, les utilisations de l’auto-identificateur peuvent amener le compilateur à émettre un avertissement et à insérer des vérifications supplémentaires pour s’assurer que les membres d’un objet ne sont pas accessibles avant l’initialisation de l’objet. Vous devez utiliser l’auto-identificateur uniquement dans les liaisons do
du constructeur principal, ou après le mot clé then
dans les constructeurs supplémentaires.
Le nom de l’auto-identificateur ne doit pas être this
. Il peut s’agir de n’importe quel identificateur valide.
Assignation de valeurs aux propriétés lors de l’initialisation
Vous pouvez attribuer des valeurs aux propriétés d’un objet de classe dans le code d’initialisation en ajoutant une liste d’affectations du formulaire property = value
à la liste d’arguments d’un constructeur. Cela est illustré par l'exemple de code suivant :
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)
La version suivante du code précédent illustre la combinaison d’arguments ordinaires, d’arguments facultatifs et de paramètres de propriété dans un appel de constructeur :
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")
Constructeurs dans la classe héritée
Lorsque vous héritez d’une classe de base qui a un constructeur, vous devez spécifier ses arguments dans la clause hériter. Pour plus d’informations, consultez Constructeurs et héritage.
Constructeurs statiques ou constructeurs de types
En plus de spécifier du code pour la création d’objets, les liaisons statiques let
et do
peuvent être créées dans des types de classes qui s’exécutent avant que le type ne soit utilisé pour effectuer l’initialisation au niveau du type. Pour plus d’informations, consultez Liaisons let
dans les classes et Liaisons do
dans les classes.
Voir aussi
- Members (Membres)