about_Classes_Constructors

Breve descrição

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 sempre têm 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 do Get-Member 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 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 parametrizada do construtor (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

Nota

O valor padrão para as propriedades Name e Author é $null porque elas são digitadas como strings, que é um tipo de referência. As outras propriedades têm o valor padrão para seu tipo definido, porque são propriedades de tipo de valor. Para obter mais informações sobre os valores padrão para propriedades, consulte "Valores de propriedade padrão" no 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 como 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 - Encadeamento de 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, esta 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 do construtor estático 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 as mensagens detalhadas para chamar os construtores de classe derivados em uma nova sessão. A primeira vez que um construtor de classe derivado é 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)

Ordenação de execução do construtor

Quando uma classe é instanciada, 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 executa 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ó são executados uma vez em uma sessão.

Para obter um exemplo de comportamento e ordem 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 de classe retornados pelo Get-Member cmdlet. Para mostrar propriedades ocultas com Get-Membero , use o parâmetro Force .
  • Não é exibido no preenchimento de tabulação ou no IntelliSense, a menos que a conclusão ocorra na classe que define a propriedade oculta.
  • Membros públicos da turma. Eles podem ser acessados e modificados. Ocultar uma propriedade não a torna privada. Apenas oculta a propriedade conforme descrito nos pontos anteriores.

Nota

Quando você oculta qualquer construtor, a new() opção é removida do IntelliSense e os resultados da 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 apenas a 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 ou métodos de instância 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 Exemplo 5.

Encadeamento de construtores

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 este 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
        }
    }
}

Gorjeta

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 validação.

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

    Alternativa: nenhuma.

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

    Alternativa: nenhuma.

Consulte também