Partager via


Constructeurs

Cet article explique 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 des types de classes ont des constructeurs. Il existe deux types de constructeurs. Il s’agit du constructeur principal, dont les paramètres apparaissent entre parenthèses juste après le nom du type. Si vous le souhaitez, vous pouvez spécifier des constructeurs supplémentaires à l’aide du new mot clé. Tous ces constructeurs supplémentaires doivent appeler le constructeur principal.

Le constructeur principal contient let et do lie des liaisons qui apparaissent au début de la définition de classe. Une let liaison déclare des champs privés et des méthodes de la classe ; une do liaison exécute du code. Pour plus d’informations sur let les liaisons dans les constructeurs de classes, consultez let Bindings in Classes. Pour plus d’informations sur do les liaisons dans les constructeurs, consultez do Liaisons dans les classes.

Quel que soit le constructeur que vous souhaitez appeler est un constructeur principal ou un constructeur supplémentaire, vous pouvez créer des objets à l’aide d’une new expression, avec ou sans le mot clé facultatif new . Vous initialisez vos objets avec des arguments de constructeur, soit en listant 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 à l’aide des noms de propriétés et attribuer des valeurs tout comme vous utilisez des arguments de constructeur nommés.

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 est la suivante :

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 newde . Toutefois, il existe une différence importante entre les structures et les classes : les structures peuvent avoir un constructeur sans paramètre (autrement dit, un avec aucun argument), 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. Les constructeurs que vous définissez pour les structures doivent avoir au moins un argument afin qu’ils ne soient pas en conflit avec le constructeur sans paramètre.

En outre, les structures ont souvent des champs créés à l’aide du val mot clé ; les classes peuvent également avoir ces champs. Les structures et classes qui ont des champs définis à l’aide du val mot clé 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 : le val mot clé.

Exécution d’effets secondaires dans les constructeurs

Un constructeur principal dans une classe peut exécuter du code dans une do liaison. Toutefois, que se passe-t-il si vous devez exécuter du code dans un constructeur supplémentaire, sans do liaison ? Pour ce faire, vous utilisez le then mot clé.

 // 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. Par conséquent, la sortie est la suivante :

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

La raison pour laquelle then est nécessaire au lieu d’une autre do est que le do mot clé a sa signification standard de limiter une unitexpression -retournant lorsqu’elle est présente dans le corps d’un constructeur supplémentaire. Elle n’a qu’une signification particulière dans le contexte des constructeurs principaux.

Identificateurs d’auto-identificateurs dans les constructeurs

Dans d’autres membres, vous fournissez un nom pour l’objet actif dans la définition de chaque membre. Vous pouvez également placer l’identificateur automatique sur la première ligne de la définition de classe à l’aide du as mot clé immédiatement après les paramètres du constructeur. L’exemple 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 as clause juste après les paramètres du constructeur. L’exemple 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 se produire lorsque vous essayez d’utiliser un objet avant qu’il soit entièrement défini. Par conséquent, les utilisations de l’identificateur automatique peuvent entraîner l’émission d’un avertissement et l’insertion de 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 uniquement utiliser l’identificateur automatique dans les do liaisons du constructeur principal, ou après le then mot clé dans des constructeurs supplémentaires.

Le nom de l’identificateur automatique n’a pas besoin d’être this. Il peut s’agir de n’importe quel identificateur valide.

Affectation de valeurs à des propriétés lors de l’initialisation

Vous pouvez affecter 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. Ceci est illustré dans 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érite. Pour plus d’informations, consultez Constructeurs et héritage.

Constructeurs statiques ou constructeurs de type

En plus de spécifier du code pour créer des objets, des liaisons et do des statiques let peuvent être créés 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 let Liaisons dans les classes et do les liaisons dans les classes.

Voir aussi