Costruttori (F#)

In questo argomento viene descritto come definire e utilizzare i costruttori per creare e inizializzare oggetti classe e struttura.

Costruzione di oggetti classe

Gli oggetti di tipo classe dispongono di costruttori. Vi sono due tipi di costruttori: uno è il costruttore primario, i cui parametri sono indicati subito dopo il nome di tipo racchiusi tra parentesi. Gli altri costruttori aggiuntivi facoltativi possono essere specificati utilizzando la parola chiave new. Qualsiasi costruttore aggiuntivo deve chiamare il costruttore primario.

Il costruttore primario contiene associazioni let e do visualizzate all'inizio della definizione di classe. Un'associazione let dichiara campi privati e metodi della classe. Un'associazione do esegue il codice. Per ulteriori informazioni sulle associazioni let nei costruttori di classe, vedere Associazioni let nelle classi (F#). Per ulteriori informazioni sulle associazioni do nei costruttori, vedere Associazioni do nelle classi (F#).

Indipendentemente dal fatto che il costruttore che si desidera chiamare sia un costruttore primario o un costruttore aggiuntivo, è possibile creare oggetti utilizzando un'espressione new, con o senza la parola chiave facoltativa new. Gli oggetti vengono inizializzati insieme agli argomenti del costruttore, elencando gli argomenti in ordine, separandoli con virgole e racchiudendoli tra parentesi oppure utilizzando argomenti denominati e valori tra parentesi. È anche possibile impostare le proprietà in un oggetto durante la costruzione dell'oggetto utilizzando i nomi delle proprietà e assegnando valori analogamente all'utilizzo di argomenti del costruttore denominati.

Nel codice seguente viene illustrata una classe con un costruttore e sono indicati i diversi modi in cui è possibile creare oggetti.

// This class has a primary constructor that takes three arguments
// and an additional constructor that calls the primary constructor.
type MyClass(x0, y0, z0) =
    let mutable x = x0
    let mutable y = y0
    let mutable z = z0
    do
        printfn "Initialized object that has coordinates (%d, %d, %d)" x y z
    member this.X with get() = x and set(value) = x <- value
    member this.Y with get() = y and set(value) = y <- value
    member this.Z with get() = z and set(value) = z <- value
    new() = MyClass(0, 0, 0)

// Create by using the new keyword.
let myObject1 = new MyClass(1, 2, 3)
// Create without using the new keyword.
let myObject2 = MyClass(4, 5, 6)
// Create by using named arguments.
let myObject3 = MyClass(x0 = 7, y0 = 8, z0 = 9)
// Create by using the additional constructor.
let myObject4 = MyClass()

L'output è indicato di seguito.

Initialized object that has coordinates (1, 2, 3)
Initialized object that has coordinates (4, 5, 6)
Initialized object that has coordinates (7, 8, 9)
Initialized object that has coordinates (0, 0, 0)

Costruzione di strutture

Le strutture seguono tutte le regole delle classi. È pertanto possibile utilizzare un costruttore primario e fornire costruttori aggiuntivi tramite new. Sussiste tuttavia una differenza fondamentale tra strutture e classi: le strutture possono disporre di un costruttore predefinito, ovvero un costruttore senza argomenti, anche se non viene definito alcun costruttore primario. Il costruttore predefinito inizializza tutti i campi in base al valore predefinito per il tipo, in genere zero o il valore equivalente. Qualsiasi costruttore definito per le strutture deve disporre di almeno un argomento in modo da non entrare in conflitto con il costruttore predefinito.

Le strutture, inoltre, dispongono spesso di campi creati utilizzando la parola chiave val. Anche le classi possono disporre di questi campi. Le strutture e le classi con campi definiti mediante la parola chiave val possono essere inizializzate in costruttori aggiuntivi anche utilizzando espressioni record, come illustrato nel codice seguente.

type MyStruct =
    struct
       val X : int
       val Y : int
       val Z : int
       new(x, y, z) = { X = x; Y = y; Z = z }
    end

let myStructure1 = new MyStruct(1, 2, 3) 

Per ulteriori informazioni, vedere Campi espliciti: parola chiave val (F#).

Esecuzione di effetti collaterali nei costruttori

Un costruttore primario in una classe può eseguire codice in un'associazione do. Talvolta, tuttavia, potrebbe essere necessario eseguire codice in un costruttore aggiuntivo, senza un'associazione do. A tale scopo, è possibile utilizzare la parola chiave then.

 // Executing side effects in the primary constructor and
// additional constructors.
type Person(nameIn : string, idIn : int) =
    let mutable name = nameIn
    let mutable id = idIn
    do printfn "Created a person object."
    member this.Name with get() = name and set(v) = name <- v
    member this.ID with get() = id and set(v) = id <- v
    new() = 
        Person("Invalid Name", -1)
        then
            printfn "Created an invalid person object."

let person1 = new Person("Humberto Acevedo", 123458734)
let person2 = new Person()

Gli effetti collaterali del costruttore primario vengono comunque eseguiti. L'output è pertanto quello indicato di seguito.

Created a person object.
Created a person object.
Created an invalid person object.

Autoidentificatori nei costruttori

Negli altri membri viene fornito un nome per l'oggetto corrente nella definizione di ogni membro. È anche possibile inserire l'autoidentificatore nella prima riga della definizione di classe utilizzando la parola chiave as subito dopo i parametri del costruttore. Questa sintassi è illustrata nell'esempio seguente.

type MyClass1(x) as this =
    // This use of the self identifier produces a warning - avoid.
    let x1 = this.X
    // This use of the self identifier is acceptable.
    do printfn "Initializing object with X =%d" this.X
    member this.X = x

Nei costruttori aggiuntivi è anche possibile definire un autoidentificatore inserendo la clausola as subito dopo i parametri del costruttore. Questa sintassi è illustrata nell'esempio seguente.

type MyClass2(x : int) =
    member this.X = x
    new() as this = MyClass2(0) then printfn "Initializing with X = %d" this.X

Quando si tenta di utilizzare un oggetto prima che sia definito completamente, possono verificarsi alcuni problemi. Gli utilizzi dello stesso identificatore possono pertanto generare l'emissione di un avviso e l'inserimento di ulteriori controlli da parte del compilatore, al fine di garantire che non venga eseguito alcun accesso a un oggetto da parte dei membri prima che venga inizializzato. Utilizzare l'autoidentificatore solo nelle associazioni do del costruttore primario o dopo la parola chiave then nei costruttori aggiuntivi.

Il nome dell'autoidentificatore non deve essere this. Può trattarsi di qualsiasi identificatore valido.

Assegnazione di valori alle proprietà al momento dell'inizializzazione

È possibile assegnare valori alle proprietà di un oggetto classe nel codice di inizializzazione aggiungendo un elenco di assegnazioni nel formato property = value all'elenco di argomenti per un costruttore. Questa operazione è illustrata nell'esempio di codice seguente.

 type Account() =
    let mutable balance = 0.0
    let mutable number = 0
    let mutable firstName = ""
    let mutable lastName = ""
    member this.AccountNumber
       with get() = number
       and set(value) = number <- value
    member this.FirstName
       with get() = firstName
       and set(value) = firstName <- value
    member this.LastName
       with get() = lastName
       and set(value) = lastName <- value
    member this.Balance
       with get() = balance
       and set(value) = balance <- value
    member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
    member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount


let account1 = new Account(AccountNumber=8782108, 
                           FirstName="Darren", LastName="Parker",
                           Balance=1543.33)

Nella versione seguente del codice precedente viene illustrata la combinazione di argomenti ordinari, argomenti facoltativi e impostazioni delle proprietà in una chiamata del costruttore.

type Account(accountNumber : int, ?first: string, ?last: string, ?bal : float) =
   let mutable balance = defaultArg bal 0.0
   let mutable number = accountNumber
   let mutable firstName = defaultArg first ""
   let mutable lastName = defaultArg last ""
   member this.AccountNumber
      with get() = number
      and set(value) = number <- value
   member this.FirstName
      with get() = firstName
      and set(value) = firstName <- value
   member this.LastName
      with get() = lastName
      and set(value) = lastName <- value
   member this.Balance
      with get() = balance
      and set(value) = balance <- value
   member this.Deposit(amount: float) = this.Balance <- this.Balance + amount
   member this.Withdraw(amount: float) = this.Balance <- this.Balance - amount


let account1 = new Account(8782108, bal = 543.33,
                          FirstName="Raman", LastName="Iyer")

Costruttori statici o costruttori di tipo

Oltre a specificare il codice per la creazione di oggetti, è possibile creare associazioni let e do statiche in tipi di classe, da eseguire prima che il tipo venga utilizzato per la prima volta per eseguire l'inizializzazione al livello del tipo. Per ulteriori informazioni, vedere Associazioni let nelle classi (F#) e Associazioni do nelle classi (F#).

Vedere anche

Concetti

Membri (F#)

Cronologia delle modifiche

Data

Cronologia

Motivo

Maggio 2010

Risoluzione di un problema nell'ultimo esempio di codice.

Correzione di bug nel contenuto.