Condividi tramite


Proprietà (F#)

Le proprietà sono membri che rappresentano i valori associati a un oggetto .

Sintassi

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

Osservazioni:

Le proprietà rappresentano la relazione "ha un" nella programmazione orientata agli oggetti, che rappresenta i dati associati alle istanze dell'oggetto o, per le proprietà statiche, con il tipo .

È possibile dichiarare le proprietà in due modi, a seconda che si voglia specificare in modo esplicito il valore sottostante (detto anche archivio di backup) per la proprietà o se si vuole consentire al compilatore di generare automaticamente l'archivio di backup. In genere, è consigliabile usare il modo più esplicito se la proprietà ha un'implementazione non semplice e il modo automatico quando la proprietà è semplicemente un wrapper semplice per un valore o una variabile. Per dichiarare una proprietà in modo esplicito, usare la member parola chiave . Questa sintassi dichiarativa è seguita dalla sintassi che specifica i get metodi e set , anche denominati funzioni di accesso. Le varie forme della sintassi esplicita illustrata nella sezione della sintassi vengono usate per proprietà di sola lettura/scrittura, di sola lettura e di sola scrittura. Per le proprietà di sola lettura, si definisce solo un get metodo. Per le proprietà di sola scrittura, definire solo un set metodo. Si noti che quando una proprietà dispone di funzioni get di accesso 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 hanno un get metodo e set , l'ordine di get e set può essere invertito. In alternativa, è possibile specificare la sintassi mostrata solo per get e la sintassi mostrata solo per set anziché usare la sintassi combinata. In questo modo è più semplice impostare come commento il singolo get metodo o set , se è necessario eseguire questa operazione. Questa alternativa all'uso 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à vengono chiamati archivi di backup. Per fare in modo che il compilatore crei automaticamente l'archivio di backup, usare le parole chiave member val, omettere l'identificatore automatico, quindi fornire un'espressione per inizializzare la proprietà. Se la proprietà deve essere modificabile, includere with get, set. Ad esempio, il tipo di classe seguente include due proprietà implementate automaticamente. Property1 è di sola lettura e viene inizializzato nell'argomento fornito al costruttore primario ed Property2 è una proprietà impostabile inizializzata su una stringa vuota:

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

Le proprietà implementate automaticamente fanno parte dell'inizializzazione di un tipo, pertanto devono essere incluse prima di qualsiasi altra definizione di membro, proprio come let associazioni e do associazioni in una definizione di tipo. Si noti che l'espressione che inizializza una proprietà implementata automaticamente viene valutata solo all'inizializzazione e non ogni volta che si accede alla proprietà. Questo comportamento è in contrasto con il comportamento di una proprietà implementata in modo esplicito. Ciò significa in modo efficace che il codice per inizializzare queste proprietà viene aggiunto al costruttore di una classe. Si consideri il codice seguente che mostra 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.ExplicitProperty = %d{class1.ExplicitProperty}"

Output

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

L'output del codice precedente mostra che il valore di AutoProperty rimane invariato quando viene chiamato ripetutamente, mentre ExplicitProperty cambia ogni volta che viene chiamato. Ciò dimostra che l'espressione per una proprietà implementata automaticamente non viene valutata ogni volta, come è il metodo getter per la proprietà esplicita.

Avviso

Esistono alcune librerie, ad esempio Entity Framework (System.Data.Entity) che eseguono operazioni personalizzate nei costruttori di classi di base che non funzionano correttamente con l'inizializzazione delle proprietà implementate automaticamente. In questi casi, provare a usare proprietà esplicite.

Le proprietà possono essere membri di classi, strutture, unioni discriminate, record, interfacce ed estensioni dei tipi e possono essere definite anche nelle espressioni oggetto.

Gli attributi possono essere applicati alle proprietà. Per applicare un attributo a una proprietà, scrivere l'attributo su una riga separata prima della proprietà . Per altre informazioni, vedere Attributi.

Per impostazione predefinita, le proprietà sono pubbliche. I modificatori di accessibilità possono essere applicati anche alle proprietà. Per applicare un modificatore di accessibilità, aggiungerlo immediatamente prima del nome della proprietà se deve essere applicato a entrambi i get metodi e set , aggiungerlo prima delle get parole chiave e set se è necessaria un'accessibilità diversa per ogni funzione di accesso. Il modificatore di accessibilità può essere uno dei seguenti: public, private, internal. Per altre informazioni, vedere Access Control.

Le implementazioni delle proprietà vengono eseguite ogni volta che si accede a una proprietà.

Proprietà statiche e dell'istanza

Le proprietà possono essere proprietà statiche o di istanza. Le proprietà statiche possono essere richiamate senza un'istanza e vengono usate per i valori associati al tipo, non con singoli oggetti. Per le proprietà statiche, omettere l'identificatore automatico. L'identificatore automatico è obbligatorio per le proprietà dell'istanza.

La definizione di proprietà statica seguente si basa su uno scenario in cui si dispone di un campo myStaticValue statico che rappresenta 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, nel qual caso vengono chiamate proprietà indicizzate. Per altre informazioni, vedere Proprietà indicizzate.

Annotazione del tipo per le proprietà

In molti casi, il compilatore dispone di informazioni sufficienti per dedurre 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

Uso delle funzioni di accesso del set di proprietà

È possibile impostare proprietà che forniscono set funzioni di accesso usando 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 per i metodi, abstract significa semplicemente che è presente un dispatch virtuale associato alla proprietà . Le proprietà astratte possono essere veramente astratte, ovvero senza una definizione nella stessa classe. La classe che contiene tale proprietà è pertanto una classe astratta. In alternativa, l'astrazione può semplicemente significare che una proprietà è virtuale e, in tal caso, una definizione deve essere presente nella stessa classe. Si noti che le proprietà astratte non devono essere private e, se una funzione di accesso è astratta, l'altra deve anche essere astratta. Per altre informazioni sulle classi astratte, vedere Classi astratte.

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

Vedi anche