Explizite Felder: Das val-Schlüsselwort
Das val
-Schlüsselwort wird zum Deklarieren eines Speicherort zum Speichern eines Werts in einer Klasse oder einem Strukturtyp verwendet, ohne ihn zu initialisieren. Speicherorte, die auf diese Weise deklariert werden, werden als explizite Felder bezeichnet. Eine weitere Verwendung des val
Schlüsselworts ist in Verbindung mit dem member
Schlüsselwort, um eine automatisch implementierte Eigenschaft zu deklarieren. Weitere Informationen zu automatisch implementierten Eigenschaften finden Sie unter "Eigenschaften".
Syntax
val [ mutable ] [ access-modifier ] field-name : type-name
Bemerkungen
In der Regel werden Felder in einer Klasse oder einem Strukturtyp durch eine let
-Bindung definiert. let
-Bindungen müssen jedoch als Teil des Klassenkonstruktors initialisiert werden, was nicht immer möglich, notwendig oder gewünscht ist. Sie können das val
-Schlüsselwort verwenden, wenn Sie ein nicht initialisiertes Feld implementieren möchten.
Explizite Felder können statisch oder nicht statisch sein. Der Zugriffsmodifizierer kann public
, private
oder internal
sein. Standardmäßig sind explizite Felder öffentlich. Dies unterscheidet sich von let
-Bindungen in Klassen, die immer privat sind.
Das DefaultValue-Attribut ist für explizite Felder in Klassentypen erforderlich, die über einen primären Konstruktor verfügen. Dieses Attribut gibt an, dass das Feld mit 0 (null) initialisiert wird. Der Typ des Felds muss die Initialisierung mit 0 (null) unterstützen. Ein Typ unterstützt die Initialisierung mit 0 (null), wenn er eine der folgenden Bedingungen erfüllt:
- Ein primitiver Typ, der einen Wert von 0 (null) hat.
- Ein Typ, der den Wert 0 (null) unterstützt, entweder als ein normaler Wert, als ein nicht normaler Wert oder als Darstellung eines Werts. Dazu gehören Klassen, Tupel, Datensätze, Funktionen, Schnittstellen, .NET-Verweistypen, der
unit
-Typ und diskriminierte Union-Typen. - Ein .NET-Werttyp.
- Eine Struktur, deren Felder alle einen Standardwert von 0 (null) unterstützen.
Ein unveränderliches Feld mit der Bezeichnung someField
verfügt zum Beispiel über ein zugrunde liegendes Feld in der kompilierten .NET-Darstellung, das someField@
heißt, und Sie greifen auf den gespeicherten Wert mit einer Eigenschaft mit der Bezeichnung someField
zu.
Bei einem veränderlichen Feld ist die kompilierte .NET-Darstellung ein .NET-Feld.
Warnung
Der .NET Framework-Namespace System.ComponentModel
enthält ein Attribut mit dem gleichen Namen. Informationen zu diesem Attribut finden Sie unter DefaultValueAttribute.
Der folgende Code zeigt die Verwendung expliziter Felder und zum Vergleich eine let
-Bindung in einer Klasse, die über einen primären Konstruktor verfügt. Beachten Sie, dass das let
-gebundene Feld myInt1
privat ist. Wenn das let
-gebundene Feld myInt1
von einer Membermethode referenziert wird, ist der Selbstbezeichner this
nicht erforderlich. Wenn Sie jedoch die expliziten Felder myInt2
und myString
referenzieren, ist der Selbstbezeichner erforderlich.
type MyType() =
let mutable myInt1 = 10
[<DefaultValue>] val mutable myInt2 : int
[<DefaultValue>] val mutable myString : string
member this.SetValsAndPrint( i: int, str: string) =
myInt1 <- i
this.myInt2 <- i + 1
this.myString <- str
printfn "%d %d %s" myInt1 (this.myInt2) (this.myString)
let myObject = new MyType()
myObject.SetValsAndPrint(11, "abc")
// The following line is not allowed because let bindings are private.
// myObject.myInt1 <- 20
myObject.myInt2 <- 30
myObject.myString <- "def"
printfn "%d %s" (myObject.myInt2) (myObject.myString)
Die Ausgabe lautet wie folgt:
11 12 abc
30 def
Der folgende Code zeigt die Verwendung von expliziten Feldern in einer Klasse, die nicht über einen primären Konstruktor verfügt. In diesem Fall ist das DefaultValue
-Attribut nicht erforderlich, es müssen jedoch alle Felder in den Konstruktoren initialisiert werden, die für den Typ definiert sind.
type MyClass =
val a : int
val b : int
// The following version of the constructor is an error
// because b is not initialized.
// new (a0, b0) = { a = a0; }
// The following version is acceptable because all fields are initialized.
new(a0, b0) = { a = a0; b = b0; }
let myClassObj = new MyClass(35, 22)
printfn "%d %d" (myClassObj.a) (myClassObj.b)
Die Ausgabe lautet 35 22
.
Der folgende Code zeigt die Verwendung von expliziten Feldern in einer Struktur. Weil eine Struktur ein Werttyp ist, verfügt sie automatisch über einen parameterlosen Standardkonstruktor, der die Werte der zugehörigen Felder auf 0 (null) festlegt. Daher ist das DefaultValue
-Attribut nicht erforderlich.
type MyStruct =
struct
val mutable myInt : int
val mutable myString : string
end
let mutable myStructObj = new MyStruct()
myStructObj.myInt <- 11
myStructObj.myString <- "xyz"
printfn "%d %s" (myStructObj.myInt) (myStructObj.myString)
Die Ausgabe lautet 11 xyz
.
Vorsicht: Wenn Sie Ihre Struktur mit mutable
-Feldern ohne das Schlüsselwort mutable
initialisieren, funktionieren Ihre Zuweisungen mit einer Kopie der Struktur, die direkt nach der Zuweisung verworfen wird. Daher ändert sich Ihre Struktur nicht.
[<Struct>]
type Foo =
val mutable bar: string
member self.ChangeBar bar = self.bar <- bar
new (bar) = {bar = bar}
let foo = Foo "1"
foo.ChangeBar "2" //make implicit copy of Foo, changes the copy, discards the copy, foo remains unchanged
printfn "%s" foo.bar //prints 1
let mutable foo' = Foo "1"
foo'.ChangeBar "2" //changes foo'
printfn "%s" foo'.bar //prints 2
Explizite Felder sind nicht für die routinemäßige Verwendung gedacht. Im Allgemeinen sollten Sie möglichst eine let
-Bindung in einer Klasse verwenden, statt eines expliziten Felds. Explizite Felder sind in bestimmten Interoperabilitätsszenarios hilfreich, wenn Sie z. B. eine Struktur definieren müssen, die in einem Plattformaufruf einer systemeigenen API oder in COM-Interop-Szenarien verwendet wird. Weitere Informationen finden Sie unter Externe Funktionen. Eine andere Situation, in der ein explizites Feld möglicherweise erforderlich, besteht dann, wenn Sie mit einem F#-Codegenerator arbeiten, der Klassen ohne primären Konstruktor ausgibt. Explizite Felder sind auch für threadstatische Variablen oder ähnliche Konstrukte sinnvoll. Weitere Informationen finden Sie unter System.ThreadStaticAttribute
.
Wenn die Schlüsselwörter member val
zusammen in einer Typdefinition angezeigt werden, handelt es sich um eine Definition einer automatisch implementierten Eigenschaft. Weitere Informationen finden Sie unter Eigenschaftendefiniert sind.