Eigenschappen (F#)
Eigenschappen zijn leden die waarden vertegenwoordigen die zijn gekoppeld aan een object.
Syntaxis
// 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 ]
Opmerkingen
Eigenschappen vertegenwoordigen de relatie 'has a' in objectgeoriënteerde programmering, die gegevens vertegenwoordigt die zijn gekoppeld aan objectexemplaren of, voor statische eigenschappen, met het type.
U kunt eigenschappen op twee manieren declareren, afhankelijk van of u expliciet de onderliggende waarde (ook wel het backing-archief genoemd) voor de eigenschap wilt opgeven, of als u wilt toestaan dat de compiler automatisch de back-upopslag voor u genereert. Over het algemeen moet u de meer expliciete manier gebruiken als de eigenschap een niet-triviale implementatie heeft en de automatische manier waarop de eigenschap slechts een eenvoudige wrapper is voor een waarde of variabele. Als u een eigenschap expliciet wilt declareren, gebruikt u het member
trefwoord. Deze declaratieve syntaxis wordt gevolgd door de syntaxis waarmee de get
en set
methoden, ook benoemde accessors, worden opgegeven. De verschillende vormen van de expliciete syntaxis die in de syntaxissectie worden weergegeven, worden gebruikt voor eigenschappen lezen/schrijven, alleen-lezen en alleen-schrijven. Voor eigenschappen met het kenmerk Alleen-lezen definieert u alleen een get
methode. Voor alleen-schrijven-eigenschappen definieert u alleen een set
methode. Wanneer een eigenschap zowel get
set
als accessors heeft, kunt u met de alternatieve syntaxis kenmerken en toegankelijkheidsaanpassingen opgeven die voor elke toegangsfunctie verschillen, zoals wordt weergegeven in de volgende code.
// 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
Voor lees-/schrijfeigenschappen, die zowel een als set
een get
methode hebben, kan de volgorde van get
en set
kunnen worden omgekeerd. U kunt ook de syntaxis opgeven die alleen wordt get
weergegeven en de syntaxis die alleen wordt set
weergegeven in plaats van de gecombineerde syntaxis te gebruiken. Als u dit doet, kunt u gemakkelijker opmerkingen maken over de persoon get
of set
methode, als dat iets is wat u mogelijk moet doen. Dit alternatief voor het gebruik van de gecombineerde syntaxis wordt weergegeven in de volgende code.
member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value
Privéwaarden die de gegevens voor eigenschappen bevatten, worden back-uparchieven genoemd. Als u wilt dat de compiler het backing-archief automatisch maakt, gebruikt u de trefwoorden member val
, laat u de self-id weg en geeft u vervolgens een expressie op om de eigenschap te initialiseren. Als de eigenschap onveranderbaar moet zijn, neemt u dit op with get, set
. Het volgende klassetype bevat bijvoorbeeld twee automatisch geïmplementeerde eigenschappen. Property1
is alleen-lezen en wordt geïnitialiseerd voor het argument dat is opgegeven voor de primaire constructor en Property2
is een settabeleigenschap die is geïnitialiseerd op een lege tekenreeks:
type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set
Automatisch geïmplementeerde eigenschappen maken deel uit van de initialisatie van een type, dus ze moeten worden opgenomen vóór andere liddefinities, net als let
bindingen en do
bindingen in een typedefinitie. Houd er rekening mee dat de expressie die een automatisch geïmplementeerde eigenschap initialiseert, alleen wordt geëvalueerd bij de initialisatie en niet telkens wanneer de eigenschap wordt geopend. Dit gedrag is in tegenstelling tot het gedrag van een expliciet geïmplementeerde eigenschap. Wat dit effectief betekent, is dat de code voor het initialiseren van deze eigenschappen wordt toegevoegd aan de constructor van een klasse. Houd rekening met de volgende code die dit verschil laat zien:
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}"
Uitvoer
class1.AutoProperty = 1853799794
class1.AutoProperty = 1853799794
class1.ExplicitProperty = 978922705
class1.ExplicitProperty = 1131210765
In de uitvoer van de voorgaande code ziet u dat de waarde van AutoProperty ongewijzigd blijft wanneer deze herhaaldelijk wordt aangeroepen, terwijl de ExplicitProperty telkens wordt gewijzigd wanneer deze wordt aangeroepen. Dit laat zien dat de expressie voor een automatisch geïmplementeerde eigenschap niet telkens wordt geëvalueerd, net zoals de gettermethode voor de expliciete eigenschap.
Waarschuwing
Er zijn enkele bibliotheken, zoals Entity Framework (System.Data.Entity
) die aangepaste bewerkingen uitvoeren in basisklasseconstructors die niet goed werken met de initialisatie van automatisch geïmplementeerde eigenschappen. Probeer in die gevallen expliciete eigenschappen te gebruiken.
Eigenschappen kunnen lid zijn van klassen, structuren, gediscrimineerde samenvoegingen, records, interfaces en typeextensies en kunnen ook worden gedefinieerd in objectexpressies.
Kenmerken kunnen worden toegepast op eigenschappen. Als u een kenmerk wilt toepassen op een eigenschap, schrijft u het kenmerk op een afzonderlijke regel vóór de eigenschap. Zie Kenmerken voor meer informatie.
Eigenschappen zijn standaard openbaar. Toegankelijkheidsaanpassingen kunnen ook worden toegepast op eigenschappen. Als u een toegankelijkheidsaanpassing wilt toepassen, voegt u deze direct vóór de naam van de eigenschap toe als deze moet worden toegepast op zowel de get
als set
de methoden. Voeg deze toe vóór de get
en set
trefwoorden als voor elke toegangsfunctie verschillende toegankelijkheid is vereist. De toegankelijkheidsaanpassing kan een van de volgende zijn: public
, private
, internal
. Zie Toegangsbeheer voor meer informatie.
Implementaties van eigenschappen worden telkens uitgevoerd wanneer een eigenschap wordt geopend.
Eigenschappen van statisch en exemplaar
Eigenschappen kunnen statische eigenschappen of exemplaareigenschappen zijn. Statische eigenschappen kunnen zonder exemplaar worden aangeroepen en worden gebruikt voor waarden die zijn gekoppeld aan het type, niet met afzonderlijke objecten. Voor statische eigenschappen laat u de self-id weg. De self-id is vereist voor exemplaareigenschappen.
De volgende definitie van statische eigenschap is gebaseerd op een scenario waarin u een statisch veld myStaticValue
hebt dat het backingarchief voor de eigenschap is.
static member MyStaticProperty
with get() = myStaticValue
and set(value) = myStaticValue <- value
Eigenschappen kunnen ook matrixachtig zijn, in dat geval worden ze geïndexeerde eigenschappen genoemd. Zie Geïndexeerde eigenschappen voor meer informatie.
Aantekening voor eigenschappen typen
In veel gevallen heeft de compiler voldoende informatie om het type eigenschap af te stellen van het type backing-archief, maar u kunt het type expliciet instellen door een typeaantekening toe te voegen.
// 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
Accessors voor eigenschappensets gebruiken
U kunt eigenschappen instellen die accessors bieden set
met behulp van de <-
operator.
// 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)
De uitvoer is 20.
Abstracte eigenschappen
Eigenschappen kunnen abstract zijn. Net als bij methoden betekent abstract
alleen dat er een virtuele verzending is gekoppeld aan de eigenschap. Abstracte eigenschappen kunnen echt abstract zijn, dat wil gezegd, zonder definitie in dezelfde klasse. De klasse die een dergelijke eigenschap bevat, is daarom een abstracte klasse. Abstract kan ook alleen betekenen dat een eigenschap virtueel is, en in dat geval moet een definitie aanwezig zijn in dezelfde klasse. Houd er rekening mee dat abstracte eigenschappen niet privé mogen zijn en als de ene accessor abstract is, moet de andere ook abstract zijn. Zie Abstract-klassen voor meer informatie over abstracte klassen.
// 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