Proprietà (F#)
Le proprietà sono membri che rappresentano valori associati a un oggetto.
// 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 ]
Note
Le proprietà rappresentano la relazione "ha" nella programmazione orientata a oggetti, rappresentando i dati associati alle istanze degli oggetti oppure, per le proprietà statiche, al tipo.
È possibile dichiarare le proprietà in due modi, a seconda se si desidera specificare in modo esplicito il valore sottostante (detto anche l'archivio di backup) per la proprietà o se si desidera consentire al compilatore di generare automaticamente l'archivio di backup per l'utente.In genere, è consigliabile utilizzare il modo più esplicito, se la proprietà dispone di un'implementazione non semplice e in modo automatico quando la proprietà è un semplice wrapper per un valore o variabile.Per dichiarare una proprietà in modo esplicito, utilizzare il member parola chiave.Questa sintassi dichiarativa viene seguita dalla sintassi che specifica i metodi get e set, detti anche funzioni di accesso.Le varie forme di sintassi esplicita illustrato nella sezione relativa alla sintassi vengono utilizzate per le proprietà di sola lettura e scrittura a sola lettura/scrittura.Per le proprietà di sola lettura, si definisce solo un metodo get. Per le proprietà di sola scrittura, si definisce solo un metodo set.Si noti che quando una proprietà dispone di entrambe le funzioni di accesso get e set, la sintassi alternativa consente di specificare attributi e modificatori di accessibilità diversi per ogni funzione di accesso, come illustrato nel codice seguente.
// 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
Per le proprietà di lettura/scrittura, che dispongono di entrambi i metodi get e set, è possibile invertire l'ordine di get e set.In alternativa, è possibile fornire la sintassi illustrata solo per get e la sintassi illustrata solo per set, anziché utilizzare la sintassi combinata.Questa operazione è più semplice rispetto a impostare come commento il singolo metodo get o set, qualora ciò sia necessario.Questa alternativa all'utilizzo della sintassi combinata è illustrata nel codice seguente.
member this.MyReadWriteProperty with get () = myInternalValue
member this.MyReadWriteProperty with set (value) = myInternalValue <- value
I valori privati che contengono i dati per le proprietà sono detti archivi di backup.Per fare in modo che il compilatore crea automaticamente l'archivio di backup, utilizzare le parole chiave member val, omettere il self-identifier, quindi fornire un'espressione per inizializzare la proprietà.Se la proprietà deve essere modificabile, includono with get, set.Ad esempio, il tipo di classe seguente include due proprietà implementata automaticamente. Property1è in sola lettura e viene inizializzato per l'argomento fornito al costruttore primario e Property2 è una proprietà impostabile inizializzata su una stringa vuota:
type MyClass(property1 : int) =
member val Property1 = property1
member val Property2 = "" with get, set
Proprietà implementate automaticamente fanno parte dell'inizializzazione di un tipo, in modo che essi devono essere inclusi come prima di altre definizioni di membro, let binding e do binding in una definizione di tipo.Si noti che viene valutata solo l'espressione che consente di inizializzare una proprietà implementata automaticamente al momento dell'inizializzazione e non ogni volta che accede alla proprietà.Questo comportamento è in contrasto con il comportamento di una proprietà implementata in modo esplicito.Ciò in modo efficace significa che il codice per inizializzare le proprietà viene aggiunta al costruttore di una classe.Si consideri il codice riportato di seguito viene illustrata questa differenza:
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.AutoProperty = %d" class1.AutoProperty
printfn "class1.ExplicitProperty = %d" class1.ExplicitProperty
printfn "class1.ExplicitProperty = %d" class1.ExplicitProperty
Output
L'output del codice precedente mostra che il valore di AutoProperty è invariato quando viene chiamato più volte, mentre il ExplicitProperty cambia ogni volta che viene chiamato.Ciò dimostra che l'espressione per una proprietà implementata automaticamente non viene valutata ogni volta che, come il metodo di richiamo della proprietà esplicite.
Attenzione |
---|
Esistono alcune librerie, ad esempio Entity Framework (System.Data.Entity) che consente di eseguire operazioni personalizzate costruttori della classe base che non funzionano correttamente con l'inizializzazione di automaticamente implementato le proprietà.In questi casi, utilizzare le proprietà esplicite. |
Le proprietà possono essere membri di classi, strutture, unioni discriminate, record, interfacce ed estensioni di tipo e possono anche essere definite nelle espressioni di oggetto.
Alle proprietà possono essere applicati attributi.Per applicare un attributo a una proprietà, scrivere l'attributo in una riga separata prima della proprietà.Per ulteriori informazioni, vedere Attributi (F#).
Per impostazione predefinita, le proprietà sono pubbliche.Alle proprietà possono essere applicati anche modificatori di accessibilità.Per applicare un modificatore di accessibilità, aggiungerlo immediatamente prima del nome della proprietà, se deve essere applicato a entrambi i metodi get e set. Aggiungerlo prima delle parole chiave get e set se è richiesto un tipo diverso di accessibilità per ogni funzione di accesso.Il valore di accessibility-modifier può essere public, private o internal.Per ulteriori informazioni, vedere Controllo di accesso (F#).
Le implementazioni delle proprietà vengono eseguite ogni volta che si effettua l'accesso a una proprietà.
Proprietà statiche e di istanza
Le proprietà possono essere statiche o di istanza.Le proprietà statiche possono essere richiamate senza un'istanza e vengono utilizzate per valori associati al tipo, non a singoli oggetti.Per le proprietà statiche, omettere il self-identifier.Il self-identifier è obbligatorio per le proprietà di istanza.
La definizione di proprietà statica seguente è basata su uno scenario in cui è presente un campo statico myStaticValue che è l'archivio di backup per la proprietà.
static member MyStaticProperty
with get() = myStaticValue
and set(value) = myStaticValue <- value
Le proprietà possono anche essere simili a matrici e in questo caso vengono dette proprietà indicizzate.Per ulteriori informazioni, vedere Proprietà indicizzate (F#).
Annotazioni di tipo per le proprietà
In molti casi, il compilatore dispone di informazioni sufficienti per derivare il tipo di una proprietà dal tipo dell'archivio di backup, ma è possibile impostare il tipo in modo esplicito aggiungendo un'annotazione di tipo.
// 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
Utilizzo delle funzioni di accesso set delle proprietà
È possibile impostare proprietà che forniscono funzioni di accesso set utilizzando l'operatore <-.
// 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)
L'output è 20.
Proprietà astratte
Le proprietà possono essere astratte.Come nel caso dei metodi, il termine astratto significa semplicemente che alla proprietà è associato un invio virtuale.Le proprietà astratte possono essere effettivamente astratte, ovvero senza una definizione nella stessa classe.La classe che contiene una proprietà di questo tipo è pertanto una classe astratta.In alternativa, il termine astratto può significare semplicemente che una proprietà è virtuale e in tal caso deve essere presente una definizione nella stessa classe.Si noti che le che proprietà astratte non devono essere private e se una funzione di accesso è astratta, anche l'altra deve esserlo.Per ulteriori informazioni sulle classi astratte, vedere Classi astratte (F#).
// 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