Condividi tramite


Campi espliciti: parola chiave val

La parola chiave val viene usata per dichiarare un percorso per archiviare un valore in un tipo di classe o struttura senza inizializzarlo. Archiviazione percorsi dichiarati in questo modo vengono chiamati campi espliciti. Un altro uso della parola chiave val è in combinazione con la parola chiave member per dichiarare una proprietà implementata automaticamente. Per altre informazioni sulle proprietà implementate automaticamente, vedere Proprietà.

Sintassi

val [ mutable ] [ access-modifier ] field-name : type-name

Osservazioni:

La modalità standard per definire i campi in un tipo di classe o struttura consiste nell'usare un'associazione let. Tuttavia, le associazioni let devono essere inizializzate come parte del costruttore della classe, ma non è sempre possibile, necessario o appropriato. È possibile usare la parola chiave val quando si desidera un campo non inizializzato.

I campi espliciti possono essere statici o non statici. Il modificatore di accesso può essere public, privateo internal. Per impostazione predefinita, i campi espliciti sono pubblici. Questo comportamento è diverso dalle associazioni let nelle classi, che invece sono sempre private.

L'attributo DefaultValue è obbligatorio nei campi espliciti nei tipi di classe con un costruttore primario. Questo attributo specifica che il campo viene inizializzato su zero. Il tipo del campo deve supportare l'inizializzazione su zero. Un tipo supporta l'inizializzazione su zero se corrisponde a uno dei seguenti tipi:

  • Un tipo primitivo con valore pari a zero.
  • Un tipo che supporta un valore null come valore normale, come valore anomalo o come rappresentazione di un valore. Questo include classi, tuple, record, funzioni, interfacce, tipi di riferimento .NET, il tipo unit e i tipi di unioni discriminati.
  • Un tipo di valore .NET.
  • Una struttura in cui tutti i campi supportano un valore predefinito pari a zero.

Ad esempio, un campo non modificabile chiamato someField è un campo di supporto nella rappresentazione compilata .NET con il nome someField@ e si accede al valore archiviato usando una proprietà denominata someField.

Per un campo modificabile, la rappresentazione compilata .NET è un campo .NET.

Avviso

Lo spazio dei nomi System.ComponentModel .NET Framework contiene un attributo con lo stesso nome. Per altre informazioni sull'attributo, vedere DefaultValueAttribute.

Nel codice seguente viene illustrato l'uso di campi espliciti e, per il confronto, un'associazione let in una classe che dispone di un costruttore primario. Si noti che il campo associato letmyInt1 è privato. Quando si fa riferimento al campo associato letmyInt1 da un metodo membro, l'autoidentificatore this non è necessario. Ma quando si fa riferimento ai campi espliciti myInt2 e myString, l'autoidentificatore è obbligatorio.

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)

L'output è il seguente:

11 12 abc
30 def

Nel codice seguente viene illustrato come usare i campi espliciti in una classe che non dispone di un costruttore principale. In questo caso, l'attributo DefaultValue non è obbligatorio, ma tutti i campi devono essere inizializzati nei costruttori definiti per il tipo.

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)

L'output è 35 22.

Nel codice seguente viene illustrato come usare i campi espliciti in una struttura. Poiché una struttura è un tipo valore, ha automaticamente un costruttore senza parametri che imposta i valori dei relativi campi su zero. Pertanto l'attributo DefaultValue non è obbligatorio.

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)

L'output è 11 xyz.

Attenzione, se si intende inizializzare la struttura con mutable campi senza mutable parola chiave, le assegnazioni funzioneranno su una copia della struttura che verrà rimossa subito dopo l'assegnazione. Pertanto, la struttura non cambierà.

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

I campi espliciti non sono destinati all'uso di routine. In generale, quando possibile è consigliabile usare un'associazione let in una classe anziché un campo esplicito. I campi espliciti sono utili in alcuni scenari di interoperabilità, ad esempio quando è necessario definire una struttura che verrà usata in una chiamata platform invoke per un'API nativa o in scenari di interoperabilità COM. Per altre informazioni, vedere Funzioni esterne. Un'altra situazione in cui un campo esplicito potrebbe essere necessario è quando si lavora con un generatore di codice F# che genera classi senza un costruttore primario. I campi espliciti sono utili anche per le variabili di thread statiche o per costrutti simili. Per ulteriori informazioni, vedere System.ThreadStaticAttribute.

Quando le parole chiave member val vengono visualizzate insieme in una definizione di tipo è una definizione di una proprietà implementata automaticamente. Per ulteriori informazioni, vedi Proprietà.

Vedi anche