about_Classes_Constructors

Descrição breve

Descreve como definir construtores para classes do PowerShell.

Descrição longa

Os construtores permitem que você defina valores padrão e valide a lógica do objeto no momento da criação da instância da classe. Os construtores têm o mesmo nome que a classe. Os construtores podem ter parâmetros para inicializar os membros de dados do novo objeto.

Os construtores de classe do PowerShell são definidos como métodos especiais na classe. Eles se comportam da mesma forma que os métodos de classe do PowerShell, com as seguintes exceções:

  • Os construtores não têm um tipo de saída. Eles não podem usar a return palavra-chave.
  • Os construtores têm sempre o mesmo nome que a classe.
  • Os construtores não podem ser chamados diretamente. Eles só são executados quando uma instância é criada.
  • Os construtores nunca aparecem na saída Get-Member do cmdlet.

Para obter mais informações sobre métodos de classe do PowerShell, consulte about_Classes_Methods.

A classe pode ter zero ou mais construtores definidos. Se nenhum construtor for definido, a classe receberá um construtor sem parâmetros padrão. Este construtor inicializa todos os membros para seus valores padrão. Tipos de objeto e cadeias de caracteres recebem valores nulos. Quando você define o construtor, nenhum construtor sem parâmetro padrão é criado. Crie um construtor sem parâmetros, se necessário.

Você também pode definir um construtor estático sem parâmetros.

Sintaxe

Os construtores de classe usam as seguintes sintaxes:

Sintaxe padrão do construtor

<class-name> () [: base([<params>])] {
    <body>
}

Sintaxe estática do construtor

static <class-name> () [: base([<params>])] {
    <body>
}

Sintaxe do construtor parametrizado (uma linha)

<class-name> ([[<parameter-type>]$<parameter-name>[, [<parameter-type>]$<parameter-name>...]]) [: base([<params>])] {
    <body>
}

Sintaxe do construtor parametrizado (multilinha)

<class-name> (
    [<parameter-type>]$<parameter-name>[,
    [<parameter-type>]$<parameter-name>...]
) [: base([<params>])] {
    <body>
}

Exemplos

Exemplo 1 - Definindo uma classe com o construtor padrão

A classe ExampleBook1 não define um construtor. Em vez disso, ele usa o construtor padrão automático.

class ExampleBook1 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn
}

[ExampleBook1]::new()
Name Author Pages PublishedOn
---- ------ ----- -----------
                0 1/1/0001 12:00:00 AM

Observação

O valor padrão para as propriedades Name e Author é $null porque elas são digitadas como cadeias de caracteres, que é um tipo de referência. As outras propriedades têm o valor padrão para seu tipo definido, porque são propriedades do tipo valor. Para obter mais informações sobre os valores padrão para propriedades, consulte "Valores de propriedade padrão" em about_Classes_Properties.

Exemplo 2 - Substituindo o construtor padrão

ExampleBook2 define explicitamente o construtor padrão, definindo os valores de PublishedOn para a data atual e Pages para 1.

class ExampleBook2 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn

    ExampleBook2() {
        $this.PublishedOn = (Get-Date).Date
        $this.Pages       = 1
    }
}

[ExampleBook2]::new()
Name Author Pages PublishedOn
---- ------ ----- -----------
                1 11/1/2023 12:00:00 AM

Exemplo 3 - Definindo sobrecargas do construtor

A classe ExampleBook3 define três sobrecargas de construtor, permitindo que os usuários criem uma instância da classe a partir de uma hashtable, passando cada valor de propriedade e passando o nome do livro e do autor. A classe não define o construtor padrão.

class ExampleBook3 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn

    ExampleBook3([hashtable]$Info) {
        switch ($Info.Keys) {
            'Name'        { $this.Name        = $Info.Name }
            'Author'      { $this.Author      = $Info.Author }
            'Pages'       { $this.Pages       = $Info.Pages }
            'PublishedOn' { $this.PublishedOn = $Info.PublishedOn }
        }
    }

    ExampleBook3(
        [string]   $Name,
        [string]   $Author,
        [int]      $Pages,
        [datetime] $PublishedOn
    ) {
        $this.Name        = $Name
        $this.Author      = $Author
        $this.Pages       = $Pages
        $this.PublishedOn = $PublishedOn
    }

    ExampleBook3([string]$Name, [string]$Author) {
        $this.Name   = $Name
        $this.Author = $Author
    }
}

[ExampleBook3]::new(@{
    Name        = 'The Hobbit'
    Author      = 'J.R.R. Tolkien'
    Pages       = 310
    PublishedOn = '1937-09-21'
})
[ExampleBook3]::new('The Hobbit', 'J.R.R. Tolkien', 310, '1937-09-21')
[ExampleBook3]::new('The Hobbit', 'J.R.R. Tolkien')
[ExampleBook3]::new()
Name       Author         Pages PublishedOn
----       ------         ----- -----------
The Hobbit J.R.R. Tolkien   310 9/21/1937 12:00:00 AM
The Hobbit J.R.R. Tolkien   310 9/21/1937 12:00:00 AM
The Hobbit J.R.R. Tolkien     0 1/1/0001 12:00:00 AM

MethodException:
Line |
  42 |  [ExampleBook3]::new()
     |  ~~~~~~~~~~~~~~~~~~~~~
     | Cannot find an overload for "new" and the argument count: "0".

Chamar o construtor padrão retorna uma exceção de método. O construtor padrão automático só é definido para uma classe quando a classe não define nenhum construtor. Como ExampleBook3 define várias sobrecargas, o construtor padrão não é adicionado automaticamente à classe.

Exemplo 4 - Encadeando construtores com um método compartilhado

Este exemplo mostra como você pode escrever código compartilhado reutilizável para construtores. As classes do PowerShell não podem usar o encadeamento de construtores, portanto, essa classe de exemplo define um Init() método. O método tem várias sobrecargas. As sobrecargas com menos parâmetros chamam as sobrecargas mais explícitas com valores padrão para os parâmetros não especificados.

class ExampleBook4 {
    [string]   $Name
    [string]   $Author
    [datetime] $PublishedOn
    [int]      $Pages

    ExampleBook4() {
        $this.Init()
    }
    ExampleBook4([string]$Name) {
        $this.Init($Name)
    }
    ExampleBook4([string]$Name, [string]$Author) {
        $this.Init($Name, $Author)
    }
    ExampleBook4([string]$Name, [string]$Author, [datetime]$PublishedOn) {
        $this.Init($Name, $Author, $PublishedOn)
    }
    ExampleBook4(
      [string]$Name,
      [string]$Author,
      [datetime]$PublishedOn,
      [int]$Pages
    ) {
        $this.Init($Name, $Author, $PublishedOn, $Pages)
    }

    hidden Init() {
        $this.Init('Unknown')
    }
    hidden Init([string]$Name) {
        $this.Init($Name, 'Unknown')
    }
    hidden Init([string]$Name, [string]$Author) {
        $this.Init($Name, $Author, (Get-Date).Date)
    }
    hidden Init([string]$Name, [string]$Author, [datetime]$PublishedOn) {
        $this.Init($Name, $Author, $PublishedOn, 1)
    }
    hidden Init(
        [string]$Name,
        [string]$Author,
        [datetime]$PublishedOn,
        [int]$Pages
      ) {
        $this.Name        = $Name
        $this.Author      = $Author
        $this.PublishedOn = $PublishedOn
        $this.Pages       = $Pages
    }
}

[ExampleBook4]::new()
[ExampleBook4]::new('The Hobbit')
[ExampleBook4]::new('The Hobbit', 'J.R.R. Tolkien')
[ExampleBook4]::new('The Hobbit', 'J.R.R. Tolkien', (Get-Date '1937-9-21'))
[ExampleBook4]::new(
    'The Hobbit',
    'J.R.R. Tolkien',
    (Get-Date '1937-9-21'),
    310
)
Name       Author         PublishedOn           Pages
----       ------         -----------           -----
Unknown    Unknown        11/1/2023 12:00:00 AM     1
The Hobbit Unknown        11/1/2023 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 11/1/2023 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 9/21/1937 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 9/21/1937 12:00:00 AM   310

Exemplo 5 - Construtores de classe derivada

Os exemplos a seguir usam classes que definem os construtores estáticos, padrão e parametrizados para uma classe base e uma classe derivada que herda da classe base.

class BaseExample {
    static [void] DefaultMessage([type]$Type) {
        Write-Verbose "[$($Type.Name)] default constructor"
    }

    static [void] StaticMessage([type]$Type) {
        Write-Verbose "[$($Type.Name)] static constructor"
    }

    static [void] ParamMessage([type]$Type, [object]$Value) {
        Write-Verbose "[$($Type.Name)] param constructor ($Value)"
    }

    static BaseExample() { [BaseExample]::StaticMessage([BaseExample])  }
    BaseExample()        { [BaseExample]::DefaultMessage([BaseExample]) }
    BaseExample($Value)  { [BaseExample]::ParamMessage([BaseExample], $Value) }
}

class DerivedExample : BaseExample {
    static DerivedExample() { [BaseExample]::StaticMessage([DerivedExample])  }
           DerivedExample() { [BaseExample]::DefaultMessage([DerivedExample]) }

    DerivedExample([int]$Number) : base($Number) {
        [BaseExample]::ParamMessage([DerivedExample], $Number)
    }
    DerivedExample([string]$String) {
        [BaseExample]::ParamMessage([DerivedExample], $String)
    }
}

O bloco a seguir mostra as mensagens detalhadas para chamar os construtores de classe base. A mensagem estática do construtor só é emitida na primeira vez que uma instância da classe é criada.

PS> $VerbosePreference = 'Continue'
PS> $b = [BaseExample]::new()

VERBOSE: [BaseExample] static constructor
VERBOSE: [BaseExample] default constructor

PS> $b = [BaseExample]::new()

VERBOSE: [BaseExample] default constructor

PS> $b = [BaseExample]::new(1)

VERBOSE: [BaseExample] param constructor (1)

O próximo bloco mostra a mensagem detalhada para chamar os construtores de classe derivada em uma nova sessão. Na primeira vez que um construtor de classe derivada é chamado, os construtores estáticos para a classe base e classe derivada são chamados. Esses construtores não são chamados novamente na sessão. Os construtores para a classe base sempre são executados antes dos construtores para a classe derivada.

PS> $VerbosePreference = 'Continue'
PS> $c = [DerivedExample]::new()

VERBOSE: [BaseExample] static constructor
VERBOSE: [DerivedExample] static constructor
VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] default constructor

PS> $c = [DerivedExample]::new()

VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] default constructor

PS> $c = [DerivedExample]::new(1)

VERBOSE: [BaseExample] param constructor (1)
VERBOSE: [DerivedExample] param constructor (1)

PS> $c = [DerivedExample]::new('foo')

VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] param constructor (foo)

Ordem de execução do construtor

Quando uma classe instancia, o código de um ou mais construtores é executado.

Para classes que não herdam de outra classe, a ordem é:

  1. O construtor estático para a classe.
  2. A sobrecarga do construtor aplicável para a classe.

Para classes derivadas que herdam de outra classe, a ordem é:

  1. O construtor estático para a classe base.
  2. O construtor estático para a classe derivada.
  3. Se o construtor de classe derivada chamar explicitamente uma sobrecarga de construtor base, ele executará esse construtor para a classe base. Se ele não chamar explicitamente um construtor base, ele executará o construtor padrão para a classe base.
  4. A sobrecarga do construtor aplicável para a classe derivada.

Em todos os casos, os construtores estáticos são executados apenas uma vez em uma sessão.

Para obter um exemplo de comportamento e ordenação do construtor, consulte o Exemplo 5.

Construtores ocultos

Você pode ocultar construtores de uma classe declarando-os com a hidden palavra-chave. Os construtores de classe oculta são:

  • Não incluído na saída padrão para a classe.
  • Não incluído na lista de membros da classe retornados pelo Get-Member cmdlet. Para mostrar propriedades ocultas com Get-Member, use o parâmetro Force .
  • Não exibido na conclusão de tabulação ou no IntelliSense, a menos que a conclusão ocorra na classe que define a propriedade oculta.
  • Membros públicos da classe. Eles podem ser acessados e modificados. Ocultar uma propriedade não a torna privada. Ele apenas oculta a propriedade conforme descrito nos pontos anteriores.

Observação

Quando você oculta qualquer construtor, a new() opção é removida do IntelliSense e dos resultados de conclusão.

Para obter mais informações sobre a hidden palavra-chave, consulte about_Hidden.

Construtores estáticos

Você pode definir um construtor como pertencente à própria classe em vez de instâncias da classe declarando o construtor com a static palavra-chave. Construtores de classe estática:

  • Invoque somente na primeira vez que uma instância da classe é criada na sessão.
  • Não é possível ter nenhum parâmetro.
  • Não é possível acessar propriedades de instância ou métodos com a $this variável.

Construtores para classes derivadas

Quando uma classe herda de outra classe, os construtores podem invocar um construtor da classe base com a base palavra-chave. Se a classe derivada não invocar explicitamente um construtor da classe base, ela invocará o construtor padrão para a classe base.

Para invocar um construtor base não padrão, adicione : base(<parameters>) após os parâmetros do construtor e antes do bloco body.

class <derived-class> : <base-class> {
    <derived-class>(<derived-parameters>) : <base-class>(<base-parameters>) {
        # initialization code
    }
}

Ao definir um construtor que chama um construtor de classe base, os parâmetros podem ser qualquer um dos seguintes itens:

  • A variável de qualquer parâmetro no construtor de classe derivada.
  • Qualquer valor estático.
  • Qualquer expressão que seja avaliada como um valor do tipo de parâmetro.

Para obter um exemplo de construtores em uma classe derivada, consulte o Exemplo 5.

Construtores de encadeamento

Ao contrário do C#, os construtores de classe do PowerShell não podem usar o encadeamento com a : this(<parameters>) sintaxe. Para reduzir a duplicação de código, use um método oculto Init() com várias sobrecargas para o mesmo efeito. O Exemplo 4 mostra uma classe usando esse padrão.

Adicionando propriedades e métodos de instância com Update-TypeData

Além de declarar propriedades e métodos diretamente na definição de classe, você pode definir propriedades para instâncias de uma classe no construtor estático usando o Update-TypeData cmdlet.

Use esse trecho como ponto de partida para o padrão. Substitua o texto do espaço reservado entre colchetes angulares, conforme necessário.

class <class-name> {
    static [hashtable[]] $MemberDefinitions = @(
        @{
            Name       = '<member-name>'
            MemberType = '<member-type>'
            Value      = <member-definition>
        }
    )

    static <class-name>() {
        $TypeName = [<class-name>].Name
        foreach ($Definition in [<class-name>]::MemberDefinitions) {
            Update-TypeData -TypeName $TypeName @Definition
        }
    }
}

Dica

O Add-Member cmdlet pode adicionar propriedades e métodos a uma classe em construtores não estáticos, mas o cmdlet é executado sempre que o construtor é chamado. Usar Update-TypeData no construtor estático garante que o código para adicionar os membros à classe só precisa ser executado uma vez em uma sessão.

Adicione propriedades à classe somente em construtores não estáticos quando elas não puderem ser definidas com Update-TypeData, como propriedades somente leitura.

Para obter mais informações sobre como definir métodos de instância com Update-TypeDatao , consulte about_Classes_Methods. Para obter mais informações sobre como definir propriedades de instância com Update-TypeDatao , consulte about_Classes_Properties.

Limitações

Os construtores de classe do PowerShell têm as seguintes limitações:

  • O encadeamento do construtor não é implementado.

    Solução alternativa: defina métodos ocultos Init() e chame-os de dentro dos construtores.

  • Os parâmetros do construtor não podem usar nenhum atributo, incluindo atributos de validação.

    Solução alternativa: reatribua os parâmetros no corpo do construtor com o atributo validation.

  • Os parâmetros do construtor não podem definir valores padrão. Os parâmetros são sempre obrigatórios.

    Solução alternativa: Não há.

  • Se qualquer sobrecarga de um construtor é ocultada, cada sobrecarga para o construtor é tratada como oculta também.

    Solução alternativa: Não há.

Confira também