Udostępnij za pośrednictwem


about_Classes_Methods

Krótki opis

Opisuje sposób definiowania metod dla klas programu PowerShell.

Długi opis

Metody definiują akcje, które może wykonywać klasa. Metody mogą przyjmować parametry określające dane wejściowe. Metody zawsze definiują typ danych wyjściowych. Jeśli metoda nie zwraca żadnych danych wyjściowych, musi mieć typ danych wyjściowych Void . Jeśli metoda nie definiuje jawnie typu danych wyjściowych, typ danych wyjściowych metody to Void.

W metodach klas żadne obiekty nie są wysyłane do potoku z wyjątkiem tych określonych w instrukcji return . Nie ma przypadkowych danych wyjściowych potoku z kodu.

Uwaga

Zasadniczo różni się to od sposobu obsługi danych wyjściowych przez funkcje programu PowerShell, gdzie wszystko przechodzi do potoku.

Błędy nieokreślone zapisywane w strumieniu błędów z wewnątrz metody klasy nie są przekazywane. Należy użyć throw polecenia , aby wyświetlić błąd zakończenia. Write-* Za pomocą poleceń cmdlet można nadal zapisywać strumienie wyjściowe programu PowerShell z poziomu metody klasy. Polecenia cmdlet przestrzegają zmiennych preferencji w zakresie wywoływania. Należy jednak unikać używania Write-* poleceń cmdlet, aby metoda zwracała tylko obiekty przy użyciu instrukcji return .

Metody klas mogą odwoływać się do bieżącego wystąpienia obiektu klasy przy użyciu $this zmiennej automatycznej w celu uzyskania dostępu do właściwości i innych metod zdefiniowanych w bieżącej klasie. Zmienna automatyczna $this nie jest dostępna w metodach statycznych.

Metody klasy mogą mieć dowolną liczbę atrybutów, w tym atrybuty ukryte i statyczne .

Składnia

Metody klas używają następujących składni:

Składnia jednowierszowa

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

Składnia wielowierszowa

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

Przykłady

Przykład 1 — minimalna definicja metody

Metoda GetVolume()klasy ExampleCube1 zwraca wolumin modułu. Definiuje typ danych wyjściowych jako liczbę zmienną i zwraca wynik mnożenia właściwości Height, Length i Width wystąpienia.

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

Przykład 2 — metoda z parametrami

Metoda GeWeight() przyjmuje zmienną liczbę wejściową dla gęstości modułu i zwraca wagę modułu obliczoną jako ilość pomnożoną przez gęstość.

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

Przykład 3 — metoda bez danych wyjściowych

W tym przykładzie zdefiniowano metodę Validate() z typem danych wyjściowych system.Void. Ta metoda nie zwraca żadnych danych wyjściowych. Zamiast tego, jeśli walidacja zakończy się niepowodzeniem, zgłasza błąd. Metoda GetVolume() wywołuje Validate() przed obliczeniem woluminu modułu. Jeśli walidacja zakończy się niepowodzeniem, metoda zakończy się przed obliczeniem.

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.

Metoda zgłasza wyjątek, ponieważ właściwości Height i Width są nieprawidłowe, uniemożliwiając klasie obliczanie bieżącego woluminu.

Przykład 4 — metoda statyczna z przeciążeniami

Klasa ExampleCube4 definiuje metodę GetVolume() statyczną z dwoma przeciążeniami. Pierwsze przeciążenie ma parametry wymiarów modułu i flagę wskazującą, czy metoda powinna zweryfikować dane wejściowe.

Drugie przeciążenie obejmuje tylko dane wejściowe liczbowe. Wywołuje pierwsze przeciążenie z parametrem $Static .$true Drugie przeciążenie daje użytkownikom sposób wywoływania metody bez konieczności definiowania, czy należy dokładnie zweryfikować dane wejściowe.

Klasa definiuje GetVolume() również jako metodę wystąpienia (niestatyczną). Ta metoda wywołuje drugie przeciążenie statyczne, zapewniając, że metoda wystąpienia GetVolume() zawsze weryfikuje wymiary modułu przed zwróceniem wartości wyjściowej.

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.

Pełne komunikaty w definicjach metody pokazują, jak początkowe wywołanie metody $this.GetVolume() wywołuje metodę statyczną.

Wywołanie metody statycznej bezpośrednio za pomocą parametru Strict jako $false zwracany 0 dla woluminu.

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

Podpisy i przeciążenia metod

Każda metoda klasy ma unikatowy podpis, który definiuje sposób wywoływania metody. Typ, nazwa i parametry metody definiują sygnaturę metody.

Gdy klasa definiuje więcej niż jedną metodę o tej samej nazwie, definicje tej metody są przeciążeniami. Przeciążenia metody muszą mieć różne parametry. Metoda nie może zdefiniować dwóch implementacji z tymi samymi parametrami, nawet jeśli typy danych wyjściowych są różne.

Poniższa klasa definiuje dwie metody i Shuffle()Deal(). Metoda Deal() definiuje dwa przeciążenia, jeden bez żadnych parametrów, a drugi z parametrem 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() })
    }
}

Dane wyjściowe metody

Domyślnie metody nie mają żadnych danych wyjściowych. Jeśli podpis metody zawiera jawny typ danych wyjściowych inny niż Void, metoda musi zwrócić obiekt tego typu. Metody nie emitują żadnych danych wyjściowych, z wyjątkiem sytuacji, gdy return słowo kluczowe jawnie zwraca obiekt.

Parametry metody

Metody klasy mogą definiować parametry wejściowe do użycia w treści metody. Parametry metody są ujęte w nawiasy i są oddzielone przecinkami. Puste nawiasy wskazują, że metoda nie wymaga żadnych parametrów.

Parametry można zdefiniować w jednym wierszu lub wielu wierszach. Poniższe bloki pokazują składnię parametrów metody.

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

Parametry metody mogą być silnie typizowane. Jeśli parametr nie jest wpisany, metoda akceptuje dowolny obiekt dla tego parametru. Jeśli parametr jest wpisany, metoda próbuje przekonwertować wartość tego parametru na poprawny typ, zgłaszając wyjątek, jeśli nie można przekonwertować danych wejściowych.

Parametry metody nie mogą definiować wartości domyślnych. Wszystkie parametry metody są obowiązkowe.

Parametry metody nie mogą mieć żadnych innych atrybutów. Zapobiega to używaniu Validate* parametrów z atrybutami. Aby uzyskać więcej informacji na temat atrybutów weryfikacji, zobacz about_Functions_Advanced_Parameters.

Aby dodać walidację do parametrów metody, możesz użyć jednego z następujących wzorców:

  1. Ponownie przypisz parametry do tych samych zmiennych przy użyciu wymaganych atrybutów weryfikacji. Działa to zarówno w przypadku metod statycznych, jak i metod wystąpień. Aby zapoznać się z przykładem tego wzorca, zobacz Przykład 4.
  2. Użyj Update-TypeData polecenia , aby zdefiniować element ScriptMethod , który używa atrybutów weryfikacji bezpośrednio w parametrach. Działa to tylko w przypadku metod wystąpień. Aby uzyskać więcej informacji, zobacz sekcję Definiowanie metod wystąpienia za pomocą metody Update-TypeData .

Zmienne automatyczne w metodach

Nie wszystkie zmienne automatyczne są dostępne w metodach. Poniższa lista zawiera zmienne automatyczne i sugestie dotyczące tego, czy i jak ich używać w metodach klas programu PowerShell. Zmienne automatyczne nieuwzględniane na liście nie są dostępne dla metod klas.

  • $? - Dostęp w zwykły sposób.
  • $_ - Dostęp w zwykły sposób.
  • $args — Zamiast tego użyj jawnych zmiennych parametrów.
  • $ConsoleFileName — Dostęp jako $Script:ConsoleFileName .
  • $Error - Dostęp w zwykły sposób.
  • $EnabledExperimentalFeatures — Dostęp jako $Script:EnabledExperimentalFeatures .
  • $Event - Dostęp w zwykły sposób.
  • $EventArgs - Dostęp w zwykły sposób.
  • $EventSubscriber - Dostęp w zwykły sposób.
  • $ExecutionContext — Dostęp jako $Script:ExecutionContext .
  • $false - Dostęp w zwykły sposób.
  • $foreach - Dostęp w zwykły sposób.
  • $HOME — Dostęp jako $Script:HOME .
  • $Host — Dostęp jako $Script:Host .
  • $input — Zamiast tego użyj jawnych zmiennych parametrów.
  • $IsCoreCLR — Dostęp jako $Script:IsCoreCLR .
  • $IsLinux — Dostęp jako $Script:IsLinux .
  • $IsMacOS — Dostęp jako $Script:IsMacOS .
  • $IsWindows — Dostęp jako $Script:IsWindows .
  • $LASTEXITCODE - Dostęp w zwykły sposób.
  • $Matches - Dostęp w zwykły sposób.
  • $MyInvocation - Dostęp w zwykły sposób.
  • $NestedPromptLevel - Dostęp w zwykły sposób.
  • $null - Dostęp w zwykły sposób.
  • $PID — Dostęp jako $Script:PID .
  • $PROFILE — Dostęp jako $Script:PROFILE .
  • $PSBoundParameters — Nie używaj tej zmiennej. Jest ona przeznaczona dla poleceń cmdlet i funkcji. Użycie go w klasie może mieć nieoczekiwane skutki uboczne.
  • $PSCmdlet — Nie używaj tej zmiennej. Jest ona przeznaczona dla poleceń cmdlet i funkcji. Użycie go w klasie może mieć nieoczekiwane skutki uboczne.
  • $PSCommandPath - Dostęp w zwykły sposób.
  • $PSCulture — Dostęp jako $Script:PSCulture .
  • $PSEdition — Dostęp jako $Script:PSEdition .
  • $PSHOME — Dostęp jako $Script:PSHOME .
  • $PSItem - Dostęp w zwykły sposób.
  • $PSScriptRoot - Dostęp w zwykły sposób.
  • $PSSenderInfo — Dostęp jako $Script:PSSenderInfo .
  • $PSUICulture — Dostęp jako $Script:PSUICulture .
  • $PSVersionTable — Dostęp jako $Script:PSVersionTable .
  • $PWD - Dostęp w zwykły sposób.
  • $Sender - Dostęp w zwykły sposób.
  • $ShellId — Dostęp jako $Script:ShellId .
  • $StackTrace - Dostęp w zwykły sposób.
  • $switch - Dostęp w zwykły sposób.
  • $this - Dostęp w zwykły sposób. W metodzie $this klasy jest zawsze bieżącym wystąpieniem klasy. Dostęp do właściwości i metod klasy można uzyskać za jego pomocą. Nie jest ona dostępna w metodach statycznych.
  • $true - Dostęp w zwykły sposób.

Aby uzyskać więcej informacji na temat zmiennych automatycznych, zobacz about_Automatic_Variables.

Metody ukryte

Metody klasy można ukryć, deklarując je za pomocą słowa kluczowego hidden . Ukryte metody klasy to:

  • Nieuwzględniane na liście składowych klas zwracanych przez Get-Member polecenie cmdlet. Aby wyświetlić ukryte metody za pomocą Get-Memberpolecenia , użyj parametru Force .
  • Nie są wyświetlane w uzupełnianiu karty lub funkcji IntelliSense, chyba że ukończenie występuje w klasie definiującej ukrytą metodę.
  • Publiczne elementy członkowskie klasy. Mogą być wywoływane i dziedziczone. Ukrywanie metody nie powoduje, że jest ona prywatna. Ukrywa tylko metodę zgodnie z opisem w poprzednich punktach.

Uwaga

Po ukryciu przeciążenia metody ta metoda zostanie usunięta z funkcji IntelliSense, wyników ukończenia i domyślnych danych wyjściowych dla metody Get-Member.

Aby uzyskać więcej informacji na temat słowa kluczowego hidden , zobacz about_Hidden.

Metody statyczne

Można zdefiniować metodę jako należącą do samej klasy zamiast wystąpień klasy, deklarując metodę za pomocą słowa kluczowego static . Metody klas statycznych:

  • Są zawsze dostępne, niezależne od wystąpienia klas.
  • Są współużytkowane we wszystkich wystąpieniach klasy.
  • Są zawsze dostępne.
  • Nie można uzyskać dostępu do właściwości wystąpienia klasy. Mogą oni uzyskiwać dostęp tylko do właściwości statycznych.
  • Na żywo dla całego zakresu sesji.

Metody klasy pochodnej

Gdy klasa pochodzi z klasy bazowej, dziedziczy metody klasy bazowej i ich przeciążenia. Wszystkie przeciążenia metody zdefiniowane w klasie bazowej, w tym ukryte metody, są dostępne w klasie pochodnej.

Klasa pochodna może zastąpić przeciążenie dziedziczonej metody przez ponowne zdefiniowanie jej w definicji klasy. Aby zastąpić przeciążenie, typy parametrów muszą być takie same jak w przypadku klasy bazowej. Typ danych wyjściowych przeciążenia może być inny.

W przeciwieństwie do konstruktorów metody nie mogą używać : base(<parameters>) składni do wywoływania przeciążenia klasy bazowej dla metody . Ponownie zdefiniowane przeciążenie klasy pochodnej całkowicie zastępuje przeciążenie zdefiniowane przez klasę bazową.

W poniższym przykładzie pokazano zachowanie metod statycznych i wystąpień w klasach pochodnych.

Klasa bazowa definiuje:

  • Metody Now() statyczne zwracania bieżącej godziny i DaysAgo() zwracania daty w przeszłości.
  • Właściwość wystąpienia TimeStamp i metoda wystąpienia, która zwraca reprezentację ToString() ciągu tej właściwości. Gwarantuje to, że gdy wystąpienie jest używane w ciągu, jest konwertowane na ciąg daty/godziny zamiast nazwy klasy.
  • Metoda SetTimeStamp() wystąpienia z dwoma przeciążeniami. Gdy metoda jest wywoływana bez parametrów, ustawia znacznik czasu na bieżący czas. Gdy metoda jest wywoływana z wartością DateTime, ustawia znacznik czasu na tę wartość.
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()
    }
}

Następny blok definiuje klasy pochodzące z klasy BaseClass:

  • Klasa DerivedClassA dziedziczy z klasy BaseClass bez żadnych przesłonięć.
  • Klasa DerivedClassB zastępuje DaysAgo() metodę statyczną, aby zwrócić reprezentację ciągu zamiast obiektu DateTime . Zastępuje również metodę ToString() wystąpienia, aby zwrócić znacznik czasu jako ciąg daty ISO8601.
  • Klasa DerivedClassC zastępuje przeciążenie bez parametrów SetTimeStamp() metody, tak aby ustawienie znacznika czasu bez parametrów ustawiało datę na 10 dni przed bieżącą datą.
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))
    }
}

Poniższy blok przedstawia dane wyjściowe metody statycznej Now() dla zdefiniowanych klas. Dane wyjściowe są takie same dla każdej klasy, ponieważ klasy pochodne nie zastępują implementacji klasy bazowej metody .

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

Następny blok wywołuje metodę statyczną DaysAgo() każdej klasy. Tylko dane wyjściowe dla klasy DerivedClassB są różne, ponieważ zastępują implementację podstawową.

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

Poniższy blok przedstawia prezentację ciągu nowego wystąpienia dla każdej klasy. Reprezentacja klasy DerivedClassB jest inna, ponieważ zastąpi metodę ToString() wystąpienia.

"`$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

Następny blok wywołuje metodę SetTimeStamp() wystąpienia dla każdego wystąpienia, ustawiając właściwość TimeStamp na określoną datę. Każde wystąpienie ma tę samą datę, ponieważ żadna z klas pochodnych nie zastępuje sparametryzowanego przeciążenia dla metody .

[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

Ostatnie wywołania SetTimeStamp() bloku bez żadnych parametrów. Dane wyjściowe pokazują, że wartość wystąpienia DerivedClassC jest ustawiona na 10 dni przed pozostałymi.

"`$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

Definiowanie metod wystąpienia za pomocą metody Update-TypeData

Poza deklarowaniem metod bezpośrednio w definicji klasy można zdefiniować metody dla wystąpień klasy w konstruktorze statycznym przy użyciu Update-TypeData polecenia cmdlet .

Użyj tego fragmentu kodu jako punktu wyjścia dla wzorca. Zastąp tekst zastępczy w nawiasach kątowych zgodnie z potrzebami.

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

Napiwek

Polecenie Add-Member cmdlet może dodawać właściwości i metody do klasy w konstruktorach niestacjonanych, ale polecenie cmdlet jest uruchamiane za każdym razem, gdy konstruktor jest wywoływany. Użycie Update-TypeData w konstruktorze statycznym gwarantuje, że kod dodawania składowych do klasy musi być uruchamiany tylko raz w sesji.

Definiowanie metod z domyślnymi wartościami parametrów i atrybutami walidacji

Metody zdefiniowane bezpośrednio w deklaracji klasy nie mogą definiować wartości domyślnych ani atrybutów weryfikacji parametrów metody. Aby zdefiniować metody klasy z domyślnymi wartościami lub atrybutami walidacji, muszą być zdefiniowane jako elementy członkowskie ScriptMethod .

W tym przykładzie klasa CardDeck definiuje metodę Draw() , która używa zarówno atrybutu weryfikacji, jak i wartości domyślnej dla parametru 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.

Uwaga

Chociaż ten wzorzec działa dla atrybutów weryfikacji, zwróć uwagę, że wyjątek jest mylący, odwołując się do braku możliwości dodania atrybutu. Może to być lepsze środowisko użytkownika, aby jawnie sprawdzić wartość parametru i zgłosić znaczący błąd. Dzięki temu użytkownicy mogą zrozumieć, dlaczego widzą błąd i co z tym zrobić.

Ograniczenia

Metody klas programu PowerShell mają następujące ograniczenia:

  • Parametry metody nie mogą używać żadnych atrybutów, w tym atrybutów walidacji.

    Obejście: Przypisz ponownie parametry w treści metody za pomocą atrybutu weryfikacji lub zdefiniuj metodę w konstruktorze statycznym za pomocą Update-TypeData polecenia cmdlet .

  • Parametry metody nie mogą definiować wartości domyślnych. Parametry są zawsze obowiązkowe.

    Obejście: Zdefiniuj metodę w konstruktorze statycznym za pomocą Update-TypeData polecenia cmdlet .

  • Metody są zawsze publiczne, nawet jeśli są ukryte. Można je przesłonić, gdy klasa jest dziedziczona.

    Obejście: brak.

  • Jeśli jakiekolwiek przeciążenie metody jest ukryte, każde przeciążenie tej metody jest również traktowane jako ukryte.

    Obejście: brak.

Zobacz też