Partilhar via


Construtores

Este artigo descreve como definir e usar construtores para criar e inicializar objetos de classe e estrutura.

Construção de objetos de classe

Objetos de tipos de classe têm construtores. Existem dois tipos de construtores. Um é o construtor primário, cujos parâmetros aparecem entre parênteses logo após o nome do tipo. Você especifica outros construtores adicionais opcionais usando a new palavra-chave. Qualquer construtor adicional deve chamar o construtor primário.

O construtor primário contém let e do associações que aparecem no início da definição de classe. Uma let ligação declara campos e métodos privados da classe, uma do associação executa código. Para obter mais informações sobre let ligações em construtores de classe, consulte let Ligações em classes. Para obter mais informações sobre do ligações em construtores, consulte do Ligações em classes.

Independentemente de o construtor que você deseja chamar é um construtor primário ou um construtor adicional, você pode criar objetos usando uma new expressão, com ou sem a palavra-chave opcional new . Você inicializa seus objetos junto com argumentos de construtor, listando os argumentos em ordem e separados por vírgulas e entre parênteses, ou usando argumentos nomeados e valores entre parênteses. Você também pode definir propriedades em um objeto durante a construção do objeto usando os nomes de propriedade e atribuindo valores da mesma forma que usa argumentos de construtor nomeado.

O código a seguir ilustra uma classe que tem um construtor e várias maneiras de criar objetos:

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

O resultado é o seguinte:

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)

Construção de estruturas

As estruturas seguem todas as regras das aulas. Portanto, você pode ter um construtor primário e pode fornecer construtores adicionais usando new. No entanto, há uma diferença importante entre estruturas e classes: estruturas podem ter um construtor sem parâmetros (ou seja, um sem argumentos) mesmo que nenhum construtor primário seja definido. O construtor sem parâmetros inicializa todos os campos para o valor padrão para esse tipo, geralmente zero ou seu equivalente. Todos os construtores que você definir para estruturas devem ter pelo menos um argumento para que eles não entrem em conflito com o construtor sem parâmetros.

Além disso, as estruturas geralmente têm campos que são criados usando a val palavra-chave, as classes também podem ter esses campos. Estruturas e classes que têm campos definidos usando a val palavra-chave também podem ser inicializadas em construtores adicionais usando expressões de registro, conforme mostrado no código a seguir.

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)

Para obter mais informações, consulte Campos explícitos: a val palavra-chave.

Execução de efeitos colaterais em construtores

Um construtor primário em uma classe pode executar código em uma do ligação. No entanto, e se você tiver que executar código em um construtor adicional, sem uma do ligação? Para fazer isso, você usa a then palavra-chave.

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

Os efeitos colaterais do construtor primário ainda são executados. Portanto, a saída é a seguinte:

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

A razão pela qual then é necessário em vez de outro do é que a do palavra-chave tem seu significado padrão de delimitar uma unitexpressão -return quando presente no corpo de um construtor adicional. Só tem um significado especial no contexto dos construtores primários.

Autoidentificadores em construtores

Em outros membros, você fornece um nome para o objeto atual na definição de cada membro. Você também pode colocar o identificador self na primeira linha da definição de classe usando a as palavra-chave imediatamente após os parâmetros do construtor. O exemplo a seguir ilustra essa sintaxe.

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

Em construtores adicionais, você também pode definir um identificador de si mesmo colocando a as cláusula logo após os parâmetros do construtor. O exemplo a seguir ilustra essa sintaxe:

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

Problemas podem ocorrer quando você tenta usar um objeto antes que ele esteja totalmente definido. Portanto, os usos do identificador automático podem fazer com que o compilador emita um aviso e insira verificações adicionais para garantir que os membros de um objeto não sejam acessados antes que o objeto seja inicializado. Você só deve usar o identificador self nas do associações do construtor primário ou após a then palavra-chave em construtores adicionais.

O nome do identificador automático não precisa ser this. Pode ser qualquer identificador válido.

Atribuindo valores a propriedades na inicialização

Você pode atribuir valores às propriedades de um objeto de classe no código de inicialização anexando uma lista de atribuições do formulário property = value à lista de argumentos de um construtor. Isso é mostrado no exemplo de código a seguir:

 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)

A seguinte versão do código anterior ilustra a combinação de argumentos ordinários, argumentos opcionais e configurações de propriedade em uma chamada de construtor:

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")

Construtores na classe herdada

Ao herdar de uma classe base que tem um construtor, você deve especificar seus argumentos na cláusula inherit. Para obter mais informações, consulte Construtores e herança.

Construtores estáticos ou construtores de tipo

Além de especificar o código para criar objetos, estáticas let e do associações podem ser criadas em tipos de classe que são executados antes que o tipo seja usado pela primeira vez para executar a inicialização no nível do tipo. Para obter mais informações, consulte let Ligações em classes e do Ligações em classes.

Consulte também