Dela via


Egenskaper (F#)

Egenskaper är medlemmar som representerar värden som är associerade med ett objekt.

Syntax

// 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 ]

Kommentarer

Egenskaper representerar relationen "har en" i objektorienterad programmering, som representerar data som är associerade med objektinstanser eller, för statiska egenskaper, med typen .

Du kan deklarera egenskaper på två sätt, beroende på om du uttryckligen vill ange det underliggande värdet (kallas även backningsarkivet) för egenskapen, eller om du vill tillåta att kompilatorn automatiskt genererar lagringsplatsen åt dig. I allmänhet bör du använda det mer explicita sättet om egenskapen har en icke-trivial implementering och det automatiska sättet när egenskapen bara är en enkel omslutning för ett värde eller en variabel. Om du vill deklarera en egenskap explicit använder du nyckelordet member . Den här deklarativa syntaxen följs av syntaxen get som anger metoderna och set , som även heter accessorer. De olika formerna av den explicita syntax som visas i syntaxavsnittet används för skriv-, skriv- och skrivskyddade egenskaper. För skrivskyddade egenskaper definierar du endast en get metod. För skrivskyddade egenskaper definierar du endast en set metod. Observera att när en egenskap har både get och set accessorer kan du med den alternativa syntaxen ange attribut och hjälpmedelsmodifierare som skiljer sig åt för varje accessor, vilket visas i följande kod.

// 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

För läs-/skrivegenskaper, som har både en get och set -metod, kan ordningen på get och set ångras. Du kan också ange den syntax som visas endast för get och den syntax som visas endast för i stället för set att använda den kombinerade syntaxen. Om du gör det blir det lättare att kommentera ut individen get eller set metoden, om det är något du kan behöva göra. Det här alternativet till att använda den kombinerade syntaxen visas i följande kod.

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

Privata värden som innehåller data för egenskaper kallas för backningslager. Om du vill att kompilatorn ska skapa lagringsplatsen automatiskt använder du nyckelorden member val, utelämnar självidentifieraren och anger sedan ett uttryck för att initiera egenskapen. Om egenskapen ska vara föränderlig inkluderar du with get, set. Följande klasstyp innehåller till exempel två automatiskt implementerade egenskaper. Property1 är skrivskyddad och initieras till argumentet som tillhandahålls till den primära konstruktorn och Property2 är en initieringsbar egenskap som initieras till en tom sträng:

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

Automatiskt implementerade egenskaper är en del av initieringen av en typ, så de måste inkluderas före andra medlemsdefinitioner, precis som let bindningar och do bindningar i en typdefinition. Observera att uttrycket som initierar en automatiskt implementerad egenskap endast utvärderas vid initiering och inte varje gång egenskapen används. Det här beteendet står i kontrast till beteendet för en explicit implementerad egenskap. Det innebär i praktiken att koden för att initiera dessa egenskaper läggs till i konstruktorn för en klass. Tänk på följande kod som visar den här skillnaden:

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}"

Output

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

Utdata från föregående kod visar att värdet för AutoProperty är oförändrat när det anropas upprepade gånger, medan ExplicitProperty ändras varje gång det anropas. Detta visar att uttrycket för en automatiskt implementerad egenskap inte utvärderas varje gång, liksom metoden getter för den explicita egenskapen.

Varning

Det finns vissa bibliotek, till exempel Entity Framework (System.Data.Entity) som utför anpassade åtgärder i basklasskonstruktorer som inte fungerar bra med initieringen av automatiskt implementerade egenskaper. I dessa fall kan du prova att använda explicita egenskaper.

Egenskaper kan vara medlemmar i klasser, strukturer, diskriminerade fackföreningar, poster, gränssnitt och typtillägg och kan också definieras i objektuttryck.

Attribut kan tillämpas på egenskaper. Om du vill tillämpa ett attribut på en egenskap skriver du attributet på en separat rad före egenskapen. Mer information finns i Attribut.

Som standard är egenskaperna offentliga. Hjälpmedelsmodifierare kan också tillämpas på egenskaper. Om du vill använda en hjälpmedelsmodifierare lägger du till den omedelbart före namnet på egenskapen om den är avsedd att gälla för både get metoderna och set . Lägg till den före nyckelorden get och set om olika hjälpmedel krävs för varje åtkomst. Hjälpmedelsmodifierarenkan vara något av följande: public, private, internal. Mer information finns i Åtkomstkontroll.

Egenskapsimplementeringar körs varje gång en egenskap används.

Egenskaper för statiska instanser och instanser

Egenskaper kan vara statiska egenskaper eller instansegenskaper. Statiska egenskaper kan anropas utan en instans och används för värden som är associerade med typen, inte med enskilda objekt. För statiska egenskaper utelämnar du självidentifieraren. Självidentifieraren krävs för instansegenskaper.

Följande statiska egenskapsdefinition baseras på ett scenario där du har ett statiskt fält myStaticValue som är lagringsplatsen för egenskapen.

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

Egenskaper kan också vara matrisliknande, i vilket fall de kallas indexerade egenskaper. Mer information finns i Indexerade egenskaper.

Skriv kommentar för egenskaper

I många fall har kompilatorn tillräckligt med information för att härleda typen av en egenskap från typen av lagringsplats, men du kan ange typen explicit genom att lägga till en typanteckning.

// 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

Använda egenskapsuppsättningsåtkomster

Du kan ange egenskaper som ger set åtkomst med hjälp av operatorn <- .

// 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)

Utdata är 20.

Abstrakta egenskaper

Egenskaper kan vara abstrakta. Precis som med metoder abstract betyder det bara att det finns en virtuell sändning som är associerad med egenskapen. Abstrakta egenskaper kan vara verkligt abstrakta, dvs. utan en definition i samma klass. Klassen som innehåller en sådan egenskap är därför en abstrakt klass. Alternativt kan abstrakt bara innebära att en egenskap är virtuell, och i så fall måste en definition finnas i samma klass. Observera att abstrakta egenskaper inte får vara privata, och om en accessor är abstrakt måste den andra också vara abstrakt. Mer information om abstrakta klasser finns i Abstrakta klasser.

// 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

Se även