Partager via


Propriétés (F#)

Les propriétés sont des membres représentant des valeurs associées à un objet.

Syntaxe

// Property that has both get and set defined.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with [accessibility-modifier] get() =
    get-function-body
and [accessibility-modifier] set parameter =
    set-function-body

// Alternative syntax for a property that has get and set.
[ attributes-for-get ]
[ static ] member [accessibility-modifier-for-get] [self-identifier.]PropertyName =
    get-function-body
[ attributes-for-set ]
[ static ] member [accessibility-modifier-for-set] [self-identifier.]PropertyName
with set parameter =
    set-function-body

// Property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName =
    get-function-body

// Alternative syntax for property that has get only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with get() =
    get-function-body

// Property that has set only.
[ attributes ]
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with set parameter =
    set-function-body

// Automatically implemented properties.
[ attributes ]
[ static ] member val [accessibility-modifier] PropertyName = initialization-expression [ with get, set ]

Notes

Les propriétés représentent la relation « a un » dans la programmation orientée objet, représentant les données associées aux instances d’objet ou, pour les propriétés statiques, au type.

Vous pouvez déclarer des propriétés de deux manières, selon que vous voulez spécifier explicitement la valeur sous-jacente (également appelée magasin de stockage) de la propriété, ou que vous voulez autoriser le compilateur à générer automatiquement le magasin de stockage pour vous. En règle générale, vous devez utiliser la méthode la plus explicite si la propriété a une implémentation non banale, et la méthode automatique si la propriété est un simple wrapper pour une valeur ou une variable. Pour déclarer explicitement une propriété, utilisez le mot clé member. Cette syntaxe déclarative est suivie de la syntaxe qui spécifie les méthodes get et set, également appelées accesseurs. Les différentes formes de syntaxe explicite indiquées dans la section de syntaxe sont utilisées pour les propriétés en lecture/écriture, en lecture seule et en écriture seule. Pour les propriétés en lecture seule, vous définissez uniquement une méthode get, pour les propriétés en écriture seule, définissez uniquement une méthode set. Notez que si une propriété a les deux accesseurs get et set, la syntaxe alternative vous permet de spécifier des attributs et des modificateurs d’accessibilité différents pour chaque accesseur, comme indiqué dans le code suivant.

// A read-only property.
member this.MyReadOnlyProperty = myInternalValue
// A write-only property.
member this.MyWriteOnlyProperty with set (value) = myInternalValue <- value
// A read-write property.
member this.MyReadWriteProperty
    with get () = myInternalValue
    and set (value) = myInternalValue <- value

Pour les propriétés en lecture/écriture, qui ont à la fois une méthode get et set, l’ordre de get et set peut être inversé. Vous pouvez également fournir la syntaxe indiquée uniquement pour get et la syntaxe indiquée uniquement pour set au lieu d’utiliser la syntaxe combinée. Cela permet de commenter plus facilement la méthode individuelle get ou set, si c’est ce que vous devez faire. Cette alternative à l’utilisation de la syntaxe combinée est illustrée dans le code suivant.

member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value

Les valeurs privées qui contiennent les données des propriétés sont appelées magasins de stockage. Pour que le compilateur crée automatiquement le magasin de stockage, utilisez les mots clés member val, omettez l’auto-identificateur, puis fournissez une expression pour initialiser la propriété. Si la propriété doit être mutable, ajoutez with get, set. Par exemple, le type de classe suivant inclut deux propriétés implémentées automatiquement. Property1 est en lecture seule et est initialisé sur l’argument fourni au constructeur principal, et Property2 est une propriété définissable initialisée sur une chaîne vide :

type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set

Les propriétés implémentées automatiquement font partie de l’initialisation d’un type. Elles doivent donc être ajoutées avant toutes les autres définitions de membre, tout comme les liaisons let et do dans une définition de type. Notez que l’expression qui initialise une propriété implémentée automatiquement est évaluée uniquement pendant l’initialisation et pas chaque fois que la propriété est consultée. Ce comportement contraste avec le comportement d’une propriété explicitement implémentée. Cela signifie en fait que le code permettant d’initialiser ces propriétés est ajouté au constructeur d’une classe. Prenons le code suivant qui montre cette différence :

type MyClass() =
    let random  = new System.Random()
    member val AutoProperty = random.Next() with get, set
    member this.ExplicitProperty = random.Next()

let class1 = new MyClass()

printfn $"class1.AutoProperty = %d{class1.AutoProperty}"
printfn $"class1.ExplicitProperty = %d{class1.ExplicitProperty}"

Sortie

class1.AutoProperty = 1853799794
class1.AutoProperty = 1853799794
class1.ExplicitProperty = 978922705
class1.ExplicitProperty = 1131210765

La sortie du code précédent montre que la valeur d’AutoProperty ne change pas quand elle est appelée à plusieurs reprises, tandis que ExplicitProperty change chaque fois qu’elle est appelée. Cela montre que l’expression d’une propriété implémentée automatiquement n’est pas évaluée à chaque fois, contrairement à la méthode getter pour la propriété explicite.

Avertissement

Certaines bibliothèques, comme Entity Framework (System.Data.Entity) effectuent des opérations personnalisées dans les constructeurs de classe de base qui ne fonctionnent pas correctement avec l’initialisation des propriétés implémentées automatiquement. Dans ce cas, essayez d’utiliser des propriétés explicites.

Les propriétés peuvent être membres de classes, de structures, d’unions discriminées, d’enregistrements, d’interfaces et d’extensions de type, et peuvent également être définies dans des expressions d’objet.

Des attributs peuvent être appliqués aux propriétés. Pour appliquer un attribut à une propriété, écrivez l’attribut sur une ligne distincte avant la propriété. Pour plus d’informations, consultez Attributs.

Par défaut, les propriétés sont publiques. Des modificateurs d’accessibilité peuvent également être appliqués aux propriétés. Pour appliquer un modificateur d’accessibilité, ajoutez-le immédiatement avant le nom de la propriété s’il doit s’appliquer aux méthodes get et set, ajoutez-le avant les mots clés get et set si une accessibilité différente est nécessaire pour chaque accesseur. accessibility-modifier peut être : public, private ou internal. Pour obtenir plus d'informations, voir Contrôle d'accès.

Les implémentations de propriété sont exécutées chaque fois qu’une propriété est consultée.

Propriétés statiques et d’instance

Les propriétés peuvent être statiques ou d’instance. Les propriétés statiques peuvent être appelées sans instance et sont utilisées pour les valeurs associées au type et non aux objets individuels. Pour les propriétés statiques, omettez l’auto-identificateur. L’auto-identificateur est nécessaire pour les propriétés d’instance.

La définition de propriété statique suivante est basée sur un scénario dans lequel le champ myStaticValue statique est le magasin de stockage de la propriété.

static member MyStaticProperty
    with get() = myStaticValue
    and set(value) = myStaticValue <- value

Les propriétés peuvent également être de type tableau, auquel cas elles sont appelées propriétés indexées. Pour plus d’informations, consultez Propriétés indexées.

Annotation de type pour les propriétés

Dans de nombreux cas, le compilateur a des informations suffisantes pour déduire le type d’une propriété à partir du type du magasin de stockage, mais vous pouvez définir le type explicitement en ajoutant une annotation de type.

// To apply a type annotation to a property that does not have an explicit
// get or set, apply the type annotation directly to the property.
member this.MyProperty1 : int = myInternalValue
// If there is a get or set, apply the type annotation to the get or set method.
member this.MyProperty2 with get() : int = myInternalValue

Utilisation d’accesseurs set de propriétés

Vous pouvez définir des propriétés qui fournissent des accesseurs set avec l’opérateur <-.

// Assume that the constructor argument sets the initial value of the
// internal backing store.
let mutable myObject = new MyType(10)
myObject.MyProperty <- 20
printfn "%d" (myObject.MyProperty)

La sortie est 20.

Propriétés abstraites

Les propriétés peuvent être abstraites. Comme pour les méthodes, abstract signifie simplement qu’une répartition virtuelle est associée à la propriété. Les propriétés abstraites peuvent être vraiment abstraites, c’est-à-dire sans définition dans la même classe. La classe qui contient ce type de propriété est donc une classe abstraite. Par ailleurs, l’abstraction peut simplement signifier qu’une propriété est virtuelle et, dans ce cas, une définition doit être présente dans la même classe. Notez que les propriétés abstraites ne doivent pas être privées et que si un accesseur est abstrait, l’autre doit également l’être. Pour plus d’informations sur les classes abstraites, consultez Classes abstraites.

// Abstract property in abstract class.
// The property is an int type that has a get and
// set method
[<AbstractClass>]
type AbstractBase() =
    abstract Property1: int with get, set

// Implementation of the abstract property
type Derived1() =
    inherit AbstractBase()
    let mutable value = 10

    override this.Property1
        with get () = value
        and set (v: int) = value <- v

// A type with a "virtual" property.
type Base1() =
    let mutable value = 10
    abstract Property1: int with get, set

    default this.Property1
        with get () = value
        and set (v: int) = value <- v

// A derived type that overrides the virtual property
type Derived2() =
    inherit Base1()
    let mutable value2 = 11

    override this.Property1
        with get () = value2
        and set (v) = value2 <- v

Voir aussi