Partilhar via


about_Classes_Methods

Breve descrição

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 usar 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 deve 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á saída acidental para o pipeline a partir do código.

Nota

Isso é fundamentalmente diferente de como as funções do PowerShell lidam com a saída, onde tudo vai para o pipeline.

Os erros não terminativos 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 return instrução.

Os métodos de classe podem fazer referência à 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 .

Sintaxe

Os métodos de classe usam as seguintes sintaxes:

Sintaxe de uma linha

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

Sintaxe de várias linhas

[[<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 pela 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. Este método não retorna nenhuma saída. Em vez disso, se a validação falhar, ele lança um erro. O GetVolume() método chama Validate() antes de calcular o volume do cubo. Se a validação falhar, o método termina 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 lança 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 de $Static como $true. A segunda sobrecarga dá aos usuários uma maneira de chamar o método sem sempre ter que 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 retornos 0 para o volume.

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

Assinaturas de método e sobrecargas

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 para 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 quaisquer parâmetros e 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 inclui um tipo de saída explícito diferente de Void, o método deve retornar um objeto desse tipo. Os métodos não emitem nenhuma saída, exceto quando a return palavra-chave retorna explicitamente um objeto.

Parâmetros do método

Os métodos de classe podem definir parâmetros de entrada para usar no corpo do método. Os parâmetros do método são colocados 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 dos parâmetros do método.

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

Os parâmetros do método podem ser fortemente tipados. 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, lançando uma exceção se a entrada não puder ser convertida.

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

Os parâmetros do 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 aos parâmetros do método:

  1. Reatribua os parâmetros às 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 o Exemplo 4.
  2. Use Update-TypeData para definir um ScriptMethod que usa atributos de validação diretamente nos parâmetros. Isso só funciona, por exemplo, métodos. 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 nos métodos. A lista a seguir inclui variáveis automáticas e sugestões sobre se e como usá-las em métodos de classe do PowerShell. As variáveis automáticas não incluídas na lista não estão disponíveis para os métodos de classe.

  • $? - Acesso normalmente.
  • $_ - Acesso normalmente.
  • $args - Em vez disso, use as variáveis de parâmetros explícitos.
  • $ConsoleFileName - Acesso como $Script:ConsoleFileName em vez disso.
  • $Error - Acesso normalmente.
  • $EnabledExperimentalFeatures - Acesso como $Script:EnabledExperimentalFeatures em vez disso.
  • $Event - Acesso normalmente.
  • $EventArgs - Acesso normalmente.
  • $EventSubscriber - Acesso normalmente.
  • $ExecutionContext - Acesso como $Script:ExecutionContext em vez disso.
  • $false - Acesso normalmente.
  • $foreach - Acesso normalmente.
  • $HOME - Acesso como $Script:HOME em vez disso.
  • $Host - Acesso como $Script:Host em vez disso.
  • $input - Em vez disso, use as variáveis de parâmetros explícitos.
  • $IsCoreCLR - Acesso como $Script:IsCoreCLR em vez disso.
  • $IsLinux - Acesso como $Script:IsLinux em vez disso.
  • $IsMacOS - Acesso como $Script:IsMacOS em vez disso.
  • $IsWindows - Acesso como $Script:IsWindows em vez disso.
  • $LASTEXITCODE - Acesso normalmente.
  • $Matches - Acesso normalmente.
  • $MyInvocation - Acesso normalmente.
  • $NestedPromptLevel - Acesso normalmente.
  • $null - Acesso normalmente.
  • $PID - Acesso como $Script:PID em vez disso.
  • $PROFILE - Acesso como $Script:PROFILE em vez disso.
  • $PSBoundParameters - Não utilize esta variável. Destina-se a cmdlets e funções. Usá-lo em uma classe pode ter efeitos colaterais inesperados.
  • $PSCmdlet - Não utilize esta variável. Destina-se a cmdlets e funções. Usá-lo em uma classe pode ter efeitos colaterais inesperados.
  • $PSCommandPath - Acesso normalmente.
  • $PSCulture - Acesso como $Script:PSCulture em vez disso.
  • $PSEdition - Acesso como $Script:PSEdition em vez disso.
  • $PSHOME - Acesso como $Script:PSHOME em vez disso.
  • $PSItem - Acesso normalmente.
  • $PSScriptRoot - Acesso normalmente.
  • $PSSenderInfo - Acesso como $Script:PSSenderInfo em vez disso.
  • $PSUICulture - Acesso como $Script:PSUICulture em vez disso.
  • $PSVersionTable - Acesso como $Script:PSVersionTable em vez disso.
  • $PWD - Acesso normalmente.
  • $Sender - Acesso normalmente.
  • $ShellId - Acesso como $Script:ShellId em vez disso.
  • $StackTrace - Acesso normalmente.
  • $switch - Acesso normalmente.
  • $this - Acesso normalmente. 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 ele. Não está disponível em métodos estáticos.
  • $true - Acesso normalmente.

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 a 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 de tabulação ou no IntelliSense, a menos que a conclusão ocorra na classe que define o método oculto.
  • Membros públicos da turma. Podem ser chamados e herdados. Ocultar um método não o torna privado. Apenas oculta o método descrito nos pontos anteriores.

Nota

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

Para obter mais informações sobre a 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 a static palavra-chave. Métodos de classe estática:

  • Estão sempre disponíveis, independentemente da instanciação da 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 durante toda a duração da sessão.

Métodos de classe derivados

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 para métodos estáticos e de instância em classes derivadas.

A classe base define:

  • Os métodos Now() estáticos 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 para a 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 para a hora atual. Quando o método é chamado com um DateTime, ele define o TimeStamp para 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 substituições.
  • 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 todas as classes, 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. Apenas a saída para DerivedClassB é diferente, porque 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 para DerivedClassB é diferente porque substituiu o ToString() método de 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 método de SetTimeStamp() instância para cada instância, definindo a propriedade TimeStamp para uma data específica. Cada instância tem a mesma data, porque 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 quaisquer parâmetros. A saída mostra que o valor para a instância 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 este trecho 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
        }
    }
}

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.

Definindo métodos com valores de parâmetros 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.

Nota

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 experiência de usuário melhor verificar 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 a respeito.

Limitações

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

  • Os parâmetros do 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 validation ou defina o método no construtor estático com o Update-TypeData cmdlet.

  • Os parâmetros do 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 escondidos. Eles podem ser substituídos quando a classe é herdada.

    Alternativa: nenhuma.

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

    Alternativa: nenhuma.

Consulte também