Eigenschaften (F#)
Eigenschaften sind Member, die einem Objekt zugeordnete Werte darstellen.
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 ]
Bemerkungen
Eigenschaften stellen die hat-Beziehung in der objektorientierten Programmierung dar, die Objektinstanzen zugeordnete Daten oder bei statischen Eigenschaften dem Typ zugeordnete Daten darstellt.
Sie können Eigenschaften auf zwei Arten deklarieren, je nachdem, ob Sie explizit den zugrunde liegenden Wert (auch als Sicherungsspeicher bezeichnet) für die Eigenschaft angeben möchten, oder ob Sie dem Compiler erlauben möchten, den Sicherungsspeicher automatisch für Sie zu generieren. Wenn die Eigenschaft über eine nicht triviale Implementierung und die automatische Methode verfügt und es sich bei der Eigenschaft nur um einen einfachen Wrapper für einen Wert oder eine Variable handelt, sollten Sie im Allgemeinen die explizitere Methode verwenden. Verwenden Sie das Schlüsselwort member
, um eine Eigenschaft explizit zu deklarieren. Auf diese deklarative Syntax folgt die Syntax, die die Methoden get
und set
angibt (auch als Zugriffsmethoden bezeichnet). Die verschiedenen Formen der expliziten Syntax im Syntaxabschnitt werden für Eigenschaften für Lese- und Schreibzugriff (read-write) sowie schreibgeschützte Eigenschaften (read-only) und lesegeschützte Eigenschaften (write-only) verwendet. Bei schreibgeschützten Eigenschaften definieren Sie nur eine get
Methode. bei lesegeschützten Eigenschaften nur eine set
-Methode. Beachten Sie, dass die alternative Syntax bei einer Eigenschaft mit den Zugriffsmethoden get
und set
wie im folgenden Code gezeigt das Angeben von Attributen und Zugriffsmodifizierern ermöglicht, die für jede Zugriffsmethode unterschiedlich sind.
// 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
Bei Eigenschaften für Lese- und Schreibzugriff, die sowohl eine get
- als auch eine set
-Methode umfassen, kann die Reihenfolge von get
und set
umgekehrt werden. Alternativ können Sie die nur für get
bzw. set
angezeigte Syntax angeben, anstatt die kombinierte Syntax zu verwenden. Dies vereinfacht bei Bedarf das Auskommentieren der einzelnen get
- bzw. set
-Methode. Diese Alternative zur Verwendung der kombinierten Syntax wird im folgenden Code gezeigt.
member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value
Private Werte, die die Daten für Eigenschaften enthalten, werden als Sicherungsspeicher bezeichnet. Verwenden Sie die Schlüsselwörter member val
, lassen Sie den Selbstbezeichner aus, und geben Sie dann einen Ausdruck zum Initialisieren der Eigenschaft an, damit der Compiler den Sicherungsspeicher automatisch erstellt. Wenn die Eigenschaft änderbar sein soll, schließen Sie with get, set
ein. Der folgende Klassentyp enthält beispielsweise zwei automatisch implementierte Eigenschaften. Property1
ist schreibgeschützt und wird für das Argument initialisiert, das für den primären Konstruktor bereitgestellt wird, und Property2
ist eine festlegbare Eigenschaft, die in eine leere Zeichenfolge initialisiert wird:
type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set
Automatisch implementierte Eigenschaften sind Teil der Initialisierung eines Typs, weshalb sie vor allen anderen Memberdefinitionen eingeschlossen werden müssen (genau wie let
- und do
-Bindungen in einer Typdefinition). Beachten Sie, dass der Ausdruck, der eine automatisch implementierte Eigenschaft initialisiert, nur bei der Initialisierung ausgewertet wird und nicht bei jedem Zugriff auf die Eigenschaft. Dieses Verhalten steht im Gegensatz zum Verhalten einer explizit implementierten Eigenschaft. Dies bedeutet effektiv, dass der Code zum Initialisieren dieser Eigenschaften dem Konstruktor einer Klasse hinzugefügt wird. Sehen Sie sich den folgenden Code an, der diesen Unterschied zeigt:
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}"
Ausgabe
class1.AutoProperty = 1853799794
class1.AutoProperty = 1853799794
class1.ExplicitProperty = 978922705
class1.ExplicitProperty = 1131210765
Die Ausgabe des vorherigen Codes zeigt, dass der Wert von „AutoProperty“ bei wiederholten Aufrufen unverändert ist, während sich „ExplicitProperty“ bei jedem Aufruf ändert. Dies zeigt, dass der Ausdruck für eine automatisch implementierte Eigenschaft nicht jedes Mal wie die Getter-Methode für die explizite Eigenschaft ausgewertet wird.
Warnung
Es gibt einige Bibliotheken wie beispielsweise das Entity Framework (System.Data.Entity
), die benutzerdefinierte Vorgänge in Basisklassenkonstruktoren ausführen, die nicht gut mit der Initialisierung automatisch implementierter Eigenschaften funktionieren. Versuchen Sie in diesen Fällen, explizite Eigenschaften zu verwenden.
Eigenschaften können Member von Klassen, Strukturen, diskriminierten Unions, Datensätzen, Schnittstellen und Typerweiterungen sein und auch in Objektausdrücken definiert werden.
Attribute können auf Eigenschaften angewendet werden. Wenn Sie ein Attribut auf eine Eigenschaft anwenden möchten, schreiben Sie das Attribut in eine separate Zeile vor der Eigenschaft. Weitere Informationen finden Sie unter Attribute.
Standardmäßig sind Eigenschaften öffentlich. Zugriffsmodifizierer können auch auf Eigenschaften angewendet werden. Wenn Sie einen Zugriffsmodifizierer auf die Methoden get
und set
anwenden möchten, fügen Sie ihn unmittelbar vor dem Namen der Eigenschaft hinzu. Fügen Sie ihn vor den Schlüsselwörtern get
und set
hinzu, wenn für jede Zugriffsmethode unterschiedliche Zugriffsberechtigungen erforderlich sind. Der Zugriffsmodifizierer kann Folgendes sein: public
, private
oder internal
. Weitere Informationen finden Sie unter Zugriffssteuerung.
Eigenschaftenimplementierungen werden jedes Mal ausgeführt, wenn auf eine Eigenschaft zugegriffen wird.
Statische Eigenschaften und Instanzeigenschaften
Eigenschaften können statisch oder Instanzeigenschaften sein. Statische Eigenschaften können ohne eine Instanz aufgerufen werden und werden für Werte verwendet, die dem Typ und nicht einzelnen Objekten zugeordnet sind. Bei statischen Eigenschaften lassen Sie den Selbstbezeichner weg. Der Selbstbezeichner ist für Instanzeigenschaften erforderlich.
Die folgende Definition für statische Eigenschaften basiert auf einem Szenario, in dem Sie über das statische Feld myStaticValue
verfügen, das als Sicherungsspeicher für die Eigenschaft fungiert.
static member MyStaticProperty
with get() = myStaticValue
and set(value) = myStaticValue <- value
Eigenschaften können auch arrayähnliche Eigenschaften sein. In diesem Fall werden sie als indizierte Eigenschaften bezeichnet. Weitere Informationen finden Sie unter Indizierte Eigenschaften.
Typanmerkung für Eigenschaften
In vielen Fällen verfügt der Compiler über genügend Informationen, um den Typ einer Eigenschaft vom Typ des Sicherungsspeichers abzuleiten. Sie können den Typ jedoch explizit festlegen, indem Sie eine Typanmerkung hinzufügen.
// 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
Verwenden von set-Zugriffsmethoden für Eigenschaften
Sie können Eigenschaften festlegen, die unter Verwendung des <-
-Operators set
-Zugriffsmethoden bereitstellen.
// 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)
Die Ausgabe lautet 20.
Abstrakte Eigenschaften
Eigenschaften können abstrakt sein. Wie bei Methoden bedeutet abstract
nur, dass der Eigenschaft ein virtueller Verteiler zugeordnet ist. Abstrakte Eigenschaften können wirklich abstrakt sein (d. h. ohne Definition in derselben Klasse vorliegen). Die Klasse, die eine solche Eigenschaft enthält, ist daher eine abstrakte Klasse. Alternativ kann abstrakt einfach bedeuten, dass eine Eigenschaft virtuell ist, und in diesem Fall muss eine Definition in derselben Klasse vorhanden sein. Beachten Sie, dass abstrakte Eigenschaften nicht privat sein dürfen, und wenn eine Zugriffsmethode abstrakt ist, muss die andere auch abstrakt sein. Weitere Informationen zu abstrakten Klassen finden Sie unter Abstrakte 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