Partager via


Propriétés (F#)

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

Syntaxe

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

// Alternative syntax for a property that has get and set.
[ static ] member [accessibility-modifier-for-get] [self-identifier.]PropertyName
with [ attributes-for-get ] get() =
    get-function-body
[ static ] member [accessibility-modifier-for-set] [self-identifier.]PropertyName
with [ attributes-for-set ] 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.
[ static ] member [accessibility-modifier] [self-identifier.]PropertyName
with [ attributes ] get() =
    get-function-body

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

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

Remarques

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

Vous pouvez déclarer des propriétés de deux façons, selon que vous souhaitez spécifier explicitement la valeur sous-jacente (également appelée magasin de stockage) pour la propriété, ou si vous souhaitez 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 triviale et la façon automatique lorsque la propriété est simplement un wrapper simple pour une valeur ou une variable. Pour déclarer explicitement une propriété, utilisez le member mot clé. Cette syntaxe déclarative est suivie de la syntaxe qui spécifie les get et set méthodes, également nommées accesseurs. Les différentes formes de la syntaxe explicite indiquée 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 get méthode ; pour les propriétés en écriture seule, définissez uniquement une set méthode. Notez que lorsqu’une propriété a des get accesseurs et set des accesseurs, 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 et get une set méthode, l’ordre et getset peuvent être inversés. Vous pouvez également fournir la syntaxe affichée uniquement get et la syntaxe affichée uniquement au set lieu d’utiliser la syntaxe combinée. Cela permet de commenter plus facilement l’individu get ou set la méthode, si c’est quelque chose que vous devrez peut-être 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, incluez 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é dans l’argument fourni au constructeur principal, et Property2 est une propriété settable 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 incluses avant toute autre définition de membre, tout comme let les liaisons et do les liaisons dans une définition de type. Notez que l’expression qui initialise une propriété implémentée automatiquement est évaluée uniquement lors de l’initialisation, et non à chaque accès à la propriété. Ce comportement est contrairement au comportement d’une propriété implémentée explicitement. Cela signifie effectivement que le code à initialiser ces propriétés est ajouté au constructeur d’une classe. Considérez 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 indique que la valeur d’un AutoProperty code est inchangée lorsqu’elle est appelée à plusieurs reprises, tandis que les ExplicitProperty modifications 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, car il s’agit de la méthode getter pour la propriété explicite.

Avertissement

Il existe certaines bibliothèques, telles que Entity Framework (System.Data.Entity) qui 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 les expressions d’objet.

Les 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. Les 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 est destiné à s’appliquer à la get fois aux méthodes et set aux méthodes ; ajoutez-le avant et getset les mots clés si une accessibilité différente est requise pour chaque accesseur. Le modificateur d’accessibilité peut être l’un des éléments suivants : public, private, internal. Pour plus d’informations, consultez Contrôle d’accès.

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

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 à des objets individuels. Pour les propriétés statiques, omettez l’identificateur automatique. L’identificateur automatique est requis pour les propriétés d’instance.

La définition de propriété statique suivante est basée sur un scénario dans lequel vous avez un champ myStaticValue statique qui 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 suffisamment d’informations 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 des accesseurs du jeu de propriétés

Vous pouvez définir des propriétés qui fournissent des set accesseurs à l’aide de 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 cela signifie simplement qu’il existe une distribution virtuelle 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 une telle propriété est donc une classe abstraite. Sinon, abstraite 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 si un accesseur est abstrait, l’autre doit également être abstrait. 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