Compartilhar via


about_Classes_Methods

Descrição breve

Descreve como definir métodos para classes do PowerShell.

Descrição longa

Os métodos definem as ações que uma classe pode executar. Os métodos podem utilizar parâmetros que especificam dados de entrada. Os métodos sempre definem um tipo de saída. Se um método não retornar nenhuma saída, ele deverá ter o tipo de saída Void . Se um método não definir explicitamente um tipo de saída, o tipo de saída do método será Void.

Em métodos de classe, nenhum objeto é enviado para o pipeline, exceto aqueles especificados na return instrução . Não há nenhuma saída acidental para o pipeline do código.

Observação

Isso é fundamentalmente diferente de como o PowerShell funciona para lidar com a saída, em que tudo vai para o pipeline.

Erros não variáveis gravados no fluxo de erros de dentro de um método de classe não são passados. Você deve usar throw para exibir um erro de encerramento. Usando os Write-* cmdlets, você ainda pode gravar nos fluxos de saída do PowerShell de dentro de um método de classe. Os cmdlets respeitam as variáveis de preferência no escopo de chamada. No entanto, você deve evitar usar os Write-* cmdlets para que o método produza apenas objetos usando a instrução return .

Os métodos de classe podem referenciar a instância atual do objeto de classe usando a $this variável automática para acessar propriedades e outros métodos definidos na classe atual. A $this variável automática não está disponível em métodos estáticos.

Os métodos de classe podem ter qualquer número de atributos, incluindo os atributos ocultos e estáticos .

Syntax

Os métodos de classe usam as seguintes sintaxes:

Sintaxe de uma linha

[[<attribute>]...] [hidden] [static] [<output-type>] <method-name> ([<method-parameters>]) { <body> }

Sintaxe multilinha

[[<attribute>]...]
[hidden]
[static]
[<output-type>] <method-name> ([<method-parameters>]) {
  <body>
}

Exemplos

Exemplo 1 – Definição mínima do método

O GetVolume() método da classe ExampleCube1 retorna o volume do cubo. Ele define o tipo de saída como um número flutuante e retorna o resultado da multiplicação das propriedades Height, Length e Width da instância.

class ExampleCube1 {
    [float]   $Height
    [float]   $Length
    [float]   $Width

    [float] GetVolume() { return $this.Height * $this.Length * $this.Width }
}

$box = [ExampleCube1]@{
    Height = 2
    Length = 2
    Width  = 3
}

$box.GetVolume()
12

Exemplo 2 – Método com parâmetros

O GeWeight() método usa uma entrada de número flutuante para a densidade do cubo e retorna o peso do cubo, calculado como volume multiplicado por densidade.

class ExampleCube2 {
    [float]   $Height
    [float]   $Length
    [float]   $Width

    [float] GetVolume() { return $this.Height * $this.Length * $this.Width }
    [float] GetWeight([float]$Density) {
        return $this.GetVolume() * $Density
    }
}

$cube = [ExampleCube2]@{
    Height = 2
    Length = 2
    Width  = 3
}

$cube.GetWeight(2.5)
30

Exemplo 3 – Método sem saída

Este exemplo define o Validate() método com o tipo de saída como System.Void. Esse método não retorna nenhuma saída. Em vez disso, se a validação falhar, ela gerará um erro. O GetVolume() método chama Validate() antes de calcular o volume do cubo. Se a validação falhar, o método será encerrado antes do cálculo.

class ExampleCube3 {
    [float]   $Height
    [float]   $Length
    [float]   $Width

    [float] GetVolume() {
        $this.Validate()

        return $this.Height * $this.Length * $this.Width
    }

    [void] Validate() {
        $InvalidProperties = @()
        foreach ($Property in @('Height', 'Length', 'Width')) {
            if ($this.$Property -le 0) {
                $InvalidProperties += $Property
            }
        }

        if ($InvalidProperties.Count -gt 0) {
            $Message = @(
                'Invalid cube properties'
                "('$($InvalidProperties -join "', '")'):"
                "Cube dimensions must all be positive numbers."
            ) -join ' '
            throw $Message
        }
    }
}

$Cube = [ExampleCube3]@{ Length = 1 ; Width = -1 }
$Cube

$Cube.GetVolume()
Height Length Width
------ ------ -----
  0.00   1.00 -1.00

Exception:
Line |
  20 |              throw $Message
     |              ~~~~~~~~~~~~~~
     | Invalid cube properties ('Height', 'Width'): Cube dimensions must
     | all be positive numbers.

O método gera uma exceção porque as propriedades Height e Width são inválidas, impedindo que a classe calcule o volume atual.

Exemplo 4 – Método estático com sobrecargas

A classe ExampleCube4 define o método GetVolume() estático com duas sobrecargas. A primeira sobrecarga tem parâmetros para as dimensões do cubo e um sinalizador para indicar se o método deve validar a entrada.

A segunda sobrecarga inclui apenas as entradas numéricas. Ele chama a primeira sobrecarga com $Static como $true. A segunda sobrecarga fornece aos usuários uma maneira de chamar o método sem sempre precisar definir se deseja validar estritamente a entrada.

A classe também define GetVolume() como um método de instância (não estático). Esse método chama a segunda sobrecarga estática, garantindo que o método de instância GetVolume() sempre valide as dimensões do cubo antes de retornar o valor de saída.

class ExampleCube4 {
    [float]   $Height
    [float]   $Length
    [float]   $Width

    static [float] GetVolume(
        [float]$Height,
        [float]$Length,
        [float]$Width,
        [boolean]$Strict
    ) {
        $Signature = "[ExampleCube4]::GetVolume({0}, {1}, {2}, {3})"
        $Signature = $Signature -f $Height, $Length, $Width, $Strict
        Write-Verbose "Called $Signature"

        if ($Strict) {
            [ValidateScript({$_ -gt 0 })]$Height = $Height
            [ValidateScript({$_ -gt 0 })]$Length = $Length
            [ValidateScript({$_ -gt 0 })]$Width  = $Width
        }

        return $Height * $Length * $Width
    }

    static [float] GetVolume([float]$Height, [float]$Length, [float]$Width) {
        $Signature = "[ExampleCube4]::GetVolume($Height, $Length, $Width)"
        Write-Verbose "Called $Signature"

        return [ExampleCube4]::GetVolume($Height, $Length, $Width, $true)
    }

    [float] GetVolume() {
        Write-Verbose "Called `$this.GetVolume()"
        return [ExampleCube4]::GetVolume(
            $this.Height,
            $this.Length,
            $this.Width
        )
    }
}

$VerbosePreference = 'Continue'
$Cube = [ExampleCube4]@{ Height = 2 ; Length = 2 }
$Cube.GetVolume()
VERBOSE: Called $this.GetVolume()
VERBOSE: Called [ExampleCube4]::GetVolume(2, 2, 0)
VERBOSE: Called [ExampleCube4]::GetVolume(2, 2, 0, True)

MetadataError:
Line |
  19 |              [ValidateScript({$_ -gt 0 })]$Width  = $Width
     |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The variable cannot be validated because the value 0 is not a valid
     | value for the Width variable.

As mensagens detalhadas nas definições de método mostram como a chamada inicial para $this.GetVolume() chama o método estático.

Chamar o método estático diretamente com o parâmetro Strict como $false retorna 0 para o volume.

[ExampleCube4]::GetVolume($Cube.Height, $Cube.Length, $Cube.Width, $false)
VERBOSE: Called [ExampleCube4]::GetVolume(2, 2, 0, False)
0

Assinaturas e sobrecargas de método

Cada método de classe tem uma assinatura exclusiva que define como chamar o método . O tipo de saída, o nome e os parâmetros do método definem a assinatura do método.

Quando uma classe define mais de um método com o mesmo nome, as definições desse método são sobrecargas. As sobrecargas de um método devem ter parâmetros diferentes. Um método não pode definir duas implementações com os mesmos parâmetros, mesmo que os tipos de saída sejam diferentes.

A classe a seguir define dois métodos, Shuffle() e Deal(). O Deal() método define duas sobrecargas, uma sem parâmetros e a outra com o parâmetro Count .

class CardDeck {
    [string[]]$Cards  = @()
    hidden [string[]]$Dealt  = @()
    hidden [string[]]$Suits  = @('Clubs', 'Diamonds', 'Hearts', 'Spades')
    hidden [string[]]$Values = 2..10 + @('Jack', 'Queen', 'King', 'Ace')

    CardDeck() {
        foreach($Suit in $this.Suits) {
            foreach($Value in $this.Values) {
                $this.Cards += "$Value of $Suit"
            }
        }
        $this.Shuffle()
    }

    [void] Shuffle() {
        $this.Cards = $this.Cards + $this.Dealt | Where-Object -FilterScript {
             -not [string]::IsNullOrEmpty($_)
        } | Get-Random -Count $this.Cards.Count
    }

    [string] Deal() {
        if ($this.Cards.Count -eq 0) { throw "There are no cards left." }

        $Card        = $this.Cards[0]
        $this.Cards  = $this.Cards[1..$this.Cards.Count]
        $this.Dealt += $Card

        return $Card
    }

    [string[]] Deal([int]$Count) {
        if ($Count -gt $this.Cards.Count) {
            throw "There are only $($this.Cards.Count) cards left."
        } elseif ($Count -lt 1) {
            throw "You must deal at least 1 card."
        }

        return (1..$Count | ForEach-Object { $this.Deal() })
    }
}

Saída do método

Por padrão, os métodos não têm nenhuma saída. Se uma assinatura de método incluir um tipo de saída explícito diferente de Void, o método deverá retornar um objeto desse tipo. Os métodos não emitem nenhuma saída, exceto quando o return palavra-chave retorna explicitamente um objeto .

Parâmetros de método

Os métodos de classe podem definir parâmetros de entrada a serem usados no corpo do método. Os parâmetros de método estão entre parênteses e separados por vírgulas. Parênteses vazios indicam que o método não requer parâmetros.

Os parâmetros podem ser definidos em uma única linha ou em várias linhas. Os blocos a seguir mostram a sintaxe para parâmetros de método.

([[<parameter-type>]]$<parameter-name>[, [[<parameter-type>]]$<parameter-name>])
(
    [[<parameter-type>]]$<parameter-name>[,
    [[<parameter-type>]]$<parameter-name>]
)

Os parâmetros de método podem ser fortemente tipado. Se um parâmetro não for digitado, o método aceitará qualquer objeto para esse parâmetro. Se o parâmetro for digitado, o método tentará converter o valor desse parâmetro para o tipo correto, gerando uma exceção se a entrada não puder ser convertida.

Os parâmetros de método não podem definir valores padrão. Todos os parâmetros de método são obrigatórios.

Os parâmetros de método não podem ter outros atributos. Isso impede que os métodos usem parâmetros com os Validate* atributos . Para obter mais informações sobre os atributos de validação, consulte about_Functions_Advanced_Parameters.

Você pode usar um dos seguintes padrões para adicionar validação a parâmetros de método:

  1. Reatribua os parâmetros para as mesmas variáveis com os atributos de validação necessários. Isso funciona para métodos estáticos e de instância. Para obter um exemplo desse padrão, consulte Exemplo 4.
  2. Use Update-TypeData para definir um ScriptMethod que usa atributos de validação diretamente nos parâmetros. Isso só funciona para métodos de instância. Para obter mais informações, consulte a seção Definindo métodos de instância com Update-TypeData .

Variáveis automáticas em métodos

Nem todas as variáveis automáticas estão disponíveis em métodos. A lista a seguir inclui variáveis automáticas e sugestões para saber se e como usá-las em métodos de classe do PowerShell. Variáveis automáticas não incluídas na lista não estão disponíveis para métodos de classe.

  • $_ - Acesso normal.
  • $args – Use as variáveis de parâmetro explícitas.
  • $ConsoleFileName – Acesse como $Script:ConsoleFileName em vez disso.
  • $Error - Acesso normal.
  • $EnabledExperimentalFeatures – Acesse como $Script:EnabledExperimentalFeatures em vez disso.
  • $Event - Acesso normal.
  • $EventArgs - Acesso normal.
  • $EventSubscriber - Acesso normal.
  • $ExecutionContext – Acesse como $Script:ExecutionContext em vez disso.
  • $false - Acesso normal.
  • $foreach - Acesso normal.
  • $HOME – Acesse como $Script:HOME em vez disso.
  • $Host – Acesse como $Script:Host em vez disso.
  • $input – Use as variáveis de parâmetro explícitas.
  • $IsCoreCLR – Acesse como $Script:IsCoreCLR em vez disso.
  • $IsLinux – Acesse como $Script:IsLinux em vez disso.
  • $IsMacOS – Acesse como $Script:IsMacOS em vez disso.
  • $IsWindows – Acesse como $Script:IsWindows em vez disso.
  • $LASTEXITCODE - Acesso normal.
  • $Matches - Acesso normal.
  • $MyInvocation - Acesso normal.
  • $NestedPromptLevel - Acesso normal.
  • $null - Acesso normal.
  • $PID – Acesse como $Script:PID em vez disso.
  • $PROFILE – Acesse como $Script:PROFILE em vez disso.
  • $PSBoundParameters - Não use essa variável. Destina-se a cmdlets e funções. Usá-lo em uma classe pode ter efeitos colaterais inesperados.
  • $PSCmdlet - Não use essa variável. Destina-se a cmdlets e funções. Usá-lo em uma classe pode ter efeitos colaterais inesperados.
  • $PSCommandPath - Acesso normal.
  • $PSCulture – Acesse como $Script:PSCulture em vez disso.
  • $PSEdition – Acesse como $Script:PSEdition em vez disso.
  • $PSHOME – Acesse como $Script:PSHOME em vez disso.
  • $PSItem - Acesso normal.
  • $PSScriptRoot - Acesso normal.
  • $PSSenderInfo – Acesse como $Script:PSSenderInfo em vez disso.
  • $PSUICulture – Acesse como $Script:PSUICulture em vez disso.
  • $PSVersionTable – Acesse como $Script:PSVersionTable em vez disso.
  • $PWD - Acesso normal.
  • $Sender - Acesso normal.
  • $ShellId – Acesse como $Script:ShellId em vez disso.
  • $StackTrace - Acesso normal.
  • $switch - Acesso normal.
  • $this - Acesso normal. Em um método de classe, $this é sempre a instância atual da classe . Você pode acessar as propriedades e os métodos da classe com ela. Ele não está disponível em métodos estáticos.
  • $true - Acesso normal.

Para obter mais informações sobre variáveis automáticas, consulte about_Automatic_Variables.

Métodos ocultos

Você pode ocultar métodos de uma classe declarando-os com o hidden palavra-chave. Os métodos de classe ocultos são:

  • Não incluído na lista de membros de classe retornados pelo Get-Member cmdlet . Para mostrar métodos ocultos com Get-Member, use o parâmetro Force .
  • Não exibido no preenchimento com tabulação ou no IntelliSense, a menos que a conclusão ocorra na classe que define o método oculto.
  • Membros públicos da classe. Eles podem ser chamados e herdados. Ocultar um método não o torna privado. Ele oculta apenas o método conforme descrito nos pontos anteriores.

Observação

Quando você oculta qualquer sobrecarga para um método, esse método é removido do IntelliSense, os resultados de conclusão e a saída padrão para Get-Member.

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

Métodos estáticos

Você pode definir um método como pertencente à própria classe em vez de instâncias da classe declarando o método com o static palavra-chave. Métodos de classe estática:

  • Estão sempre disponíveis, independentemente da instanciação de classe.
  • São compartilhados em todas as instâncias da classe .
  • Estão sempre disponíveis.
  • Não é possível acessar as propriedades da instância da classe . Eles só podem acessar propriedades estáticas.
  • Ao vivo para todo o intervalo de sessão.

Métodos de classe derivada

Quando uma classe deriva de uma classe base, ela herda os métodos da classe base e suas sobrecargas. Todas as sobrecargas de método definidas na classe base, incluindo métodos ocultos, estão disponíveis na classe derivada.

Uma classe derivada pode substituir uma sobrecarga de método herdada redefinindo-a na definição de classe. Para substituir a sobrecarga, os tipos de parâmetro devem ser os mesmos da classe base. O tipo de saída para a sobrecarga pode ser diferente.

Ao contrário dos construtores, os métodos não podem usar a : base(<parameters>) sintaxe para invocar uma sobrecarga de classe base para o método . A sobrecarga redefinida na classe derivada substitui completamente a sobrecarga definida pela classe base.

O exemplo a seguir mostra o comportamento de métodos estáticos e de instância em classes derivadas.

A classe base define:

  • Os métodos estáticos Now() para retornar a hora atual e DaysAgo() para retornar uma data no passado.
  • A propriedade de instância TimeStamp e um ToString() método de instância que retorna a representação de cadeia de caracteres dessa propriedade. Isso garante que, quando uma instância é usada em uma cadeia de caracteres, ela é convertida na cadeia de caracteres datetime em vez do nome da classe.
  • O método SetTimeStamp() de instância com duas sobrecargas. Quando o método é chamado sem parâmetros, ele define o TimeStamp como a hora atual. Quando o método é chamado com um DateTime, ele define o TimeStamp como esse valor.
class BaseClass {
    static [datetime] Now() {
        return Get-Date
    }
    static [datetime] DaysAgo([int]$Count) {
        return [BaseClass]::Now().AddDays(-$Count)
    }

    [datetime] $TimeStamp = [BaseClass]::Now()

    [string] ToString() {
        return $this.TimeStamp.ToString()
    }

    [void] SetTimeStamp([datetime]$TimeStamp) {
        $this.TimeStamp = $TimeStamp
    }
    [void] SetTimeStamp() {
        $this.TimeStamp = [BaseClass]::Now()
    }
}

O próximo bloco define classes derivadas de BaseClass:

  • DerivedClassA herda de BaseClass sem nenhuma substituição.
  • DerivedClassB substitui o DaysAgo() método estático para retornar uma representação de cadeia de caracteres em vez do objeto DateTime . Ele também substitui o ToString() método de instância para retornar o carimbo de data/hora como uma cadeia de caracteres de data ISO8601.
  • DerivedClassC substitui a sobrecarga sem parâmetros do SetTimeStamp() método para que a configuração do carimbo de data/hora sem parâmetros defina a data como 10 dias antes da data atual.
class DerivedClassA : BaseClass     {}
class DerivedClassB : BaseClass     {
    static [string] DaysAgo([int]$Count) {
        return [BaseClass]::DaysAgo($Count).ToString('yyyy-MM-dd')
    }
    [string] ToString() {
        return $this.TimeStamp.ToString('yyyy-MM-dd')
    }
}
class DerivedClassC : BaseClass {
    [void] SetTimeStamp() {
        $this.SetTimeStamp([BaseClass]::Now().AddDays(-10))
    }
}

O bloco a seguir mostra a saída do método estático Now() para as classes definidas. A saída é a mesma para cada classe, porque as classes derivadas não substituem a implementação da classe base do método .

"[BaseClass]::Now()     => $([BaseClass]::Now())"
"[DerivedClassA]::Now() => $([DerivedClassA]::Now())"
"[DerivedClassB]::Now() => $([DerivedClassB]::Now())"
"[DerivedClassC]::Now() => $([DerivedClassC]::Now())"
[BaseClass]::Now()     => 11/06/2023 09:41:23
[DerivedClassA]::Now() => 11/06/2023 09:41:23
[DerivedClassB]::Now() => 11/06/2023 09:41:23
[DerivedClassC]::Now() => 11/06/2023 09:41:23

O próximo bloco chama o DaysAgo() método estático de cada classe. Somente a saída de DerivedClassB é diferente, pois ela substituiu a implementação base.

"[BaseClass]::DaysAgo(3)     => $([BaseClass]::DaysAgo(3))"
"[DerivedClassA]::DaysAgo(3) => $([DerivedClassA]::DaysAgo(3))"
"[DerivedClassB]::DaysAgo(3) => $([DerivedClassB]::DaysAgo(3))"
"[DerivedClassC]::DaysAgo(3) => $([DerivedClassC]::DaysAgo(3))"
[BaseClass]::DaysAgo(3)     => 11/03/2023 09:41:38
[DerivedClassA]::DaysAgo(3) => 11/03/2023 09:41:38
[DerivedClassB]::DaysAgo(3) => 2023-11-03
[DerivedClassC]::DaysAgo(3) => 11/03/2023 09:41:38

O bloco a seguir mostra a apresentação de cadeia de caracteres de uma nova instância para cada classe. A representação de DerivedClassB é diferente porque substituiu o método de ToString() instância.

"`$base = [BaseClass]::New()     => $($base = [BaseClass]::New(); $base)"
"`$a    = [DerivedClassA]::New() => $($a = [DerivedClassA]::New(); $a)"
"`$b    = [DerivedClassB]::New() => $($b = [DerivedClassB]::New(); $b)"
"`$c    = [DerivedClassC]::New() => $($c = [DerivedClassC]::New(); $c)"
$base = [BaseClass]::New()     => 11/6/2023 9:44:57 AM
$a    = [DerivedClassA]::New() => 11/6/2023 9:44:57 AM
$b    = [DerivedClassB]::New() => 2023-11-06
$c    = [DerivedClassC]::New() => 11/6/2023 9:44:57 AM

O próximo bloco chama o SetTimeStamp() método de instância para cada instância, definindo a propriedade TimeStamp como uma data específica. Cada instância tem a mesma data, pois nenhuma das classes derivadas substitui a sobrecarga parametrizada para o método .

[datetime]$Stamp = '2024-10-31'
"`$base.SetTimeStamp(`$Stamp) => $($base.SetTimeStamp($Stamp) ; $base)"
"`$a.SetTimeStamp(`$Stamp)    => $($a.SetTimeStamp($Stamp); $a)"
"`$b.SetTimeStamp(`$Stamp)    => $($b.SetTimeStamp($Stamp); $b)"
"`$c.SetTimeStamp(`$Stamp)    => $($c.SetTimeStamp($Stamp); $c)"
$base.SetTimeStamp($Stamp) => 10/31/2024 12:00:00 AM
$a.SetTimeStamp($Stamp)    => 10/31/2024 12:00:00 AM
$b.SetTimeStamp($Stamp)    => 2024-10-31
$c.SetTimeStamp($Stamp)    => 10/31/2024 12:00:00 AM

O último bloco chama SetTimeStamp() sem parâmetros. A saída mostra que o valor da instância de DerivedClassC é definido como 10 dias antes dos outros.

"`$base.SetTimeStamp() => $($base.SetTimeStamp() ; $base)"
"`$a.SetTimeStamp()    => $($a.SetTimeStamp(); $a)"
"`$b.SetTimeStamp()    => $($b.SetTimeStamp(); $b)"
"`$c.SetTimeStamp()    => $($c.SetTimeStamp(); $c)"
$base.SetTimeStamp() => 11/6/2023 9:53:58 AM
$a.SetTimeStamp()    => 11/6/2023 9:53:58 AM
$b.SetTimeStamp()    => 2023-11-06
$c.SetTimeStamp()    => 10/27/2023 9:53:58 AM

Definindo métodos de instância com Update-TypeData

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

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

class <ClassName> {
    static [hashtable[]] $MemberDefinitions = @(
        @{
            MemberName = '<MethodName>'
            MemberType = 'ScriptMethod'
            Value      = {
              param(<method-parameters>)

              <method-body>
            }
        }
    )

    static <ClassName>() {
        $TypeName = [<ClassName>].Name
        foreach ($Definition in [<ClassName>]::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.

Definindo métodos com valores de parâmetro padrão e atributos de validação

Os métodos definidos diretamente em uma declaração de classe não podem definir valores padrão ou atributos de validação nos parâmetros do método. Para definir métodos de classe com valores padrão ou atributos de validação, eles devem ser definidos como membros ScriptMethod .

Neste exemplo, a classe CardDeck define um Draw() método que usa um atributo de validação e um valor padrão para o parâmetro Count .

class CookieJar {
    [int] $Cookies = 12

    static [hashtable[]] $MemberDefinitions = @(
        @{
            MemberName = 'Eat'
            MemberType = 'ScriptMethod'
            Value      = {
                param(
                    [ValidateScript({ $_ -ge 1 -and $_ -le $this.Cookies })]
                    [int] $Count = 1
                )

                $this.Cookies -= $Count
                if ($Count -eq 1) {
                    "You ate 1 cookie. There are $($this.Cookies) left."
                } else {
                    "You ate $Count cookies. There are $($this.Cookies) left."
                }
            }
        }
    )

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

$Jar = [CookieJar]::new()
$Jar.Eat(1)
$Jar.Eat()
$Jar.Eat(20)
$Jar.Eat(6)
You ate 1 cookie. There are 11 left.

You ate 1 cookie. There are 10 left.

MethodInvocationException:
Line |
  36 |  $Jar.Eat(20)
     |  ~~~~~~~~~~~~
     | Exception calling "Eat" with "1" argument(s): "The attribute
     | cannot be added because variable Count with value 20 would no
     | longer be valid."

You ate 6 cookies. There are 4 left.

Observação

Embora esse padrão funcione para atributos de validação, observe que a exceção é enganosa, fazendo referência a uma incapacidade de adicionar um atributo. Pode ser uma melhor experiência do usuário marcar explicitamente o valor do parâmetro e gerar um erro significativo. Dessa forma, os usuários podem entender por que estão vendo o erro e o que fazer sobre ele.

Limitações

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

  • Os parâmetros de método não podem usar nenhum atributo, incluindo atributos de validação.

    Solução alternativa: reatribua os parâmetros no corpo do método com o atributo de validação ou defina o método no construtor estático com o Update-TypeData cmdlet .

  • Os parâmetros de método não podem definir valores padrão. Os parâmetros são sempre obrigatórios.

    Solução alternativa: defina o método no construtor estático com o Update-TypeData cmdlet .

  • Os métodos são sempre públicos, mesmo quando estão ocultos. Eles podem ser substituídos quando a classe é herdada.

    Solução alternativa: nenhuma.

  • Se qualquer sobrecarga de um método estiver oculta, cada sobrecarga desse método também será tratada como oculta.

    Solução alternativa: nenhuma.

Confira também