Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Krótki opis
Opisuje sposób używania klas do tworzenia własnych typów niestandardowych.
Długi opis
Program PowerShell 5.0 dodaje formalną składnię do definiowania klas i innych typów zdefiniowanych przez użytkownika. Dodanie klas umożliwia deweloperom i specjalistom IT korzystanie z programu PowerShell w szerszym zakresie przypadków użycia. Upraszcza tworzenie artefaktów programu PowerShell i przyspiesza pokrycie powierzchni zarządzania.
Deklaracja klasy to strategia używana do tworzenia wystąpień obiektów w czasie wykonywania. Podczas definiowania klasy nazwa klasy jest nazwą typu. Jeśli na przykład zadeklarujesz klasę o nazwie Urządzenie i zainicjujesz zmienną $dev
do nowego wystąpienia urządzenia, $dev
jest obiektem lub wystąpieniem typu Urządzenie. Każde wystąpienie urządzenia może mieć różne wartości we właściwościach.
Obsługiwane scenariusze
- Zdefiniuj typy niestandardowe w programie PowerShell przy użyciu znanych semantyki programowania obiektowego, takich jak klasy, właściwości, metody, dziedziczenie itp.
- Debugowanie typów przy użyciu języka programu PowerShell.
- Generowanie i obsługa wyjątków przy użyciu mechanizmów formalnych.
- Zdefiniuj zasoby DSC i skojarzone z nimi typy przy użyciu języka programu PowerShell.
Składnia
Klasy są deklarowane przy użyciu następującej składni:
class <class-name> [: [<base-class>][,<interface-list]] {
[[<attribute>] [hidden] [static] <property-definition> ...]
[<class-name>([<constructor-argument-list>])
{<constructor-statement-list>} ...]
[[<attribute>] [hidden] [static] <method-definition> ...]
}
Klasy są tworzone przy użyciu jednej z następujących składni:
[$<variable-name> =] New-Object -TypeName <class-name> [
[-ArgumentList] <constructor-argument-list>]
[$<variable-name> =] [<class-name>]::new([<constructor-argument-list>])
Uwaga
W przypadku korzystania ze [<class-name>]::new(
składni nawiasy wokół nazwy klasy są obowiązkowe. Nawiasy sygnalizujące definicję typu dla programu PowerShell.
Przykładowa składnia i użycie
W tym przykładzie przedstawiono minimalną składnię wymaganą do utworzenia klasy użytecznej.
class Device {
[string]$Brand
}
$dev = [Device]::new()
$dev.Brand = "Microsoft"
$dev
Brand
-----
Microsoft
Właściwości klasy
Właściwości to zmienne zadeklarowane w zakresie klasy. Właściwość może być dowolnego typu wbudowanego lub wystąpienia innej klasy. Klasy nie mają ograniczenia liczby właściwości, które mają.
Przykładowa klasa z prostymi właściwościami
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
}
$device = [Device]::new()
$device.Brand = "Microsoft"
$device.Model = "Surface Pro 4"
$device.VendorSku = "5072641000"
$device
Brand Model VendorSku
----- ----- ---------
Microsoft Surface Pro 4 5072641000
Przykładowe typy złożone we właściwościach klasy
W tym przykładzie zdefiniowano pustą klasę Rack przy użyciu klasy Device . Poniższe przykłady pokazują, jak dodać urządzenia do stojaka i jak zacząć od wstępnie załadowanego stojaka.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
}
class Rack {
[string]$Brand
[string]$Model
[string]$VendorSku
[string]$AssetId
[Device[]]$Devices = [Device[]]::new(8)
}
$rack = [Rack]::new()
$rack
Brand :
Model :
VendorSku :
AssetId :
Devices : {$null, $null, $null, $null...}
Metody klas
Metody definiują akcje, które może wykonywać klasa. Metody mogą przyjmować parametry zapewniające dane wejściowe. Metody mogą zwracać dane wyjściowe. Dane zwracane przez metodę mogą być dowolnym zdefiniowanym typem danych.
Przykład prostej klasy z właściwościami i metodami
Rozszerzenie klasy Rack w celu dodania i usunięcia urządzeń do lub z niej.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
[string]ToString(){
return ("{0}|{1}|{2}" -f $this.Brand, $this.Model, $this.VendorSku)
}
}
class Rack {
[int]$Slots = 8
[string]$Brand
[string]$Model
[string]$VendorSku
[string]$AssetId
[Device[]]$Devices = [Device[]]::new($this.Slots)
[void] AddDevice([Device]$dev, [int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $dev
}
[void]RemoveDevice([int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $null
}
[int[]] GetAvailableSlots(){
[int]$i = 0
return @($this.Devices.foreach{ if($_ -eq $null){$i}; $i++})
}
}
$rack = [Rack]::new()
$surface = [Device]::new()
$surface.Brand = "Microsoft"
$surface.Model = "Surface Pro 4"
$surface.VendorSku = "5072641000"
$rack.AddDevice($surface, 2)
$rack
$rack.GetAvailableSlots()
Slots : 8
Brand :
Model :
VendorSku :
AssetId :
Devices : {$null, $null, Microsoft|Surface Pro 4|5072641000, $null...}
0
1
3
4
5
6
7
Dane wyjściowe w metodach klas
Metody powinny mieć zdefiniowany typ zwracany. Jeśli metoda nie zwraca danych wyjściowych, typ danych wyjściowych powinien mieć wartość [void]
.
W metodach klas żadne obiekty nie są wysyłane do potoku, z wyjątkiem tych wymienionych w instrukcji return
. Nie ma przypadkowych danych wyjściowych potoku z kodu.
Uwaga
Różni się to zasadniczo od sposobu obsługi danych wyjściowych przez funkcje programu PowerShell, gdzie wszystko przechodzi do potoku.
Dane wyjściowe metody
W tym przykładzie nie przedstawiono przypadkowych danych wyjściowych potoku z metod klas, z wyjątkiem instrukcji return
.
class FunWithIntegers
{
[int[]]$Integers = 0..10
[int[]]GetOddIntegers(){
return $this.Integers.Where({ ($_ % 2) })
}
[void] GetEvenIntegers(){
# this following line doesn't go to the pipeline
$this.Integers.Where({ ($_ % 2) -eq 0})
}
[string]SayHello(){
# this following line doesn't go to the pipeline
"Good Morning"
# this line goes to the pipeline
return "Hello World"
}
}
$ints = [FunWithIntegers]::new()
$ints.GetOddIntegers()
$ints.GetEvenIntegers()
$ints.SayHello()
1
3
5
7
9
Hello World
Konstruktor
Konstruktory umożliwiają ustawianie wartości domyślnych i weryfikowanie logiki obiektu w momencie tworzenia wystąpienia klasy. Konstruktory mają taką samą nazwę jak klasa. Konstruktory mogą mieć argumenty, aby zainicjować składowe danych nowego obiektu.
Klasa może mieć zdefiniowane zero lub więcej konstruktorów. Jeśli żaden konstruktor nie jest zdefiniowany, klasa otrzymuje domyślny konstruktor bez parametrów. Ten konstruktor inicjuje wszystkie elementy członkowskie do ich wartości domyślnych. Typy obiektów i ciągi mają wartości null. Podczas definiowania konstruktora nie jest tworzony domyślny konstruktor bez parametrów. Twórca konstruktora bez parametrów, jeśli jest potrzebny.
Składnia podstawowa konstruktora
W tym przykładzie klasa Device jest definiowana z właściwościami i konstruktorem. Aby użyć tej klasy, użytkownik musi podać wartości parametrów wymienionych w konstruktorze.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
Device(
[string]$b,
[string]$m,
[string]$vsk
){
$this.Brand = $b
$this.Model = $m
$this.VendorSku = $vsk
}
}
[Device]$surface = [Device]::new("Microsoft", "Surface Pro 4", "5072641000")
$surface
Brand Model VendorSku
----- ----- ---------
Microsoft Surface Pro 4 5072641000
Przykład z wieloma konstruktorami
W tym przykładzie klasa Device jest definiowana z właściwościami, konstruktorem domyślnym i konstruktorem do inicjowania wystąpienia.
Domyślny konstruktor ustawia markę na wartość Niezdefiniowane i pozostawia model i jednostkę SKU dostawcy z wartościami null.
class Device {
[string]$Brand
[string]$Model
[string]$VendorSku
Device(){
$this.Brand = 'Undefined'
}
Device(
[string]$b,
[string]$m,
[string]$vsk
){
$this.Brand = $b
$this.Model = $m
$this.VendorSku = $vsk
}
}
[Device]$somedevice = [Device]::new()
[Device]$surface = [Device]::new("Microsoft", "Surface Pro 4", "5072641000")
$somedevice
$surface
Brand Model VendorSku
----- ----- ---------
Undefined
Microsoft Surface Pro 4 5072641000
Atrybut ukryty
Atrybut hidden
sprawia, że właściwość lub metoda jest mniej widoczna. Właściwość lub metoda jest nadal dostępna dla użytkownika i jest dostępna we wszystkich zakresach, w których obiekt jest dostępny. Ukryte elementy członkowskie są ukryte w poleceniu Get-Member
cmdlet i nie można ich wyświetlić przy użyciu uzupełniania karty ani funkcji IntelliSense poza definicją klasy.
Przykład użycia ukrytych atrybutów
Po utworzeniu obiektu rack liczba miejsc dla urządzeń jest stałą wartością, która nie powinna być zmieniana w żadnym momencie. Ta wartość jest znana w czasie tworzenia.
Użycie ukrytego atrybutu umożliwia deweloperowi przechowywanie ukrytej liczby miejsc i uniemożliwia niezamierzone zmiany rozmiaru stojaka.
class Device {
[string]$Brand
[string]$Model
}
class Rack {
[int] hidden $Slots = 8
[string]$Brand
[string]$Model
[Device[]]$Devices = [Device[]]::new($this.Slots)
Rack ([string]$b, [string]$m, [int]$capacity){
## argument validation here
$this.Brand = $b
$this.Model = $m
$this.Slots = $capacity
## reset rack size to new capacity
$this.Devices = [Device[]]::new($this.Slots)
}
}
[Rack]$r1 = [Rack]::new("Microsoft", "Surface Pro 4", 16)
$r1
$r1.Devices.Length
$r1.Slots
Brand Model Devices
----- ----- -------
Microsoft Surface Pro 4 {$null, $null, $null, $null...}
16
16
Zwróć uwagę, że właściwość Sloty nie jest wyświetlana w $r1
danych wyjściowych. Jednak rozmiar został zmieniony przez konstruktora.
Atrybut statyczny
Atrybut static
definiuje właściwość lub metodę, która istnieje w klasie i nie wymaga wystąpienia.
Właściwość statyczna jest zawsze dostępna, niezależnie od wystąpienia klasy. Właściwość statyczna jest współużytkowana we wszystkich wystąpieniach klasy. Metoda statyczna jest zawsze dostępna. Wszystkie właściwości statyczne są aktywne dla całego zakresu sesji.
Przykład użycia atrybutów statycznych i metod
Załóżmy, że stojaki utworzone w tym miejscu istnieją w centrum danych. Dlatego chcesz śledzić stojaki w kodzie.
class Device {
[string]$Brand
[string]$Model
}
class Rack {
hidden [int] $Slots = 8
static [Rack[]]$InstalledRacks = @()
[string]$Brand
[string]$Model
[string]$AssetId
[Device[]]$Devices = [Device[]]::new($this.Slots)
Rack ([string]$b, [string]$m, [string]$id, [int]$capacity){
## argument validation here
$this.Brand = $b
$this.Model = $m
$this.AssetId = $id
$this.Slots = $capacity
## reset rack size to new capacity
$this.Devices = [Device[]]::new($this.Slots)
## add rack to installed racks
[Rack]::InstalledRacks += $this
}
static [void]PowerOffRacks(){
foreach ($rack in [Rack]::InstalledRacks) {
Write-Warning ("Turning off rack: " + ($rack.AssetId))
}
}
}
Testowanie właściwości statycznej i metody istnieje
PS> [Rack]::InstalledRacks.Length
0
PS> [Rack]::PowerOffRacks()
PS> (1..10) | ForEach-Object {
>> [Rack]::new("Adatum Corporation", "Standard-16",
>> $_.ToString("Std0000"), 16)
>> } > $null
PS> [Rack]::InstalledRacks.Length
10
PS> [Rack]::InstalledRacks[3]
Brand Model AssetId Devices
----- ----- ------- -------
Adatum Corporation Standard-16 Std0004 {$null, $null, $null, $null...}
PS> [Rack]::PowerOffRacks()
WARNING: Turning off rack: Std0001
WARNING: Turning off rack: Std0002
WARNING: Turning off rack: Std0003
WARNING: Turning off rack: Std0004
WARNING: Turning off rack: Std0005
WARNING: Turning off rack: Std0006
WARNING: Turning off rack: Std0007
WARNING: Turning off rack: Std0008
WARNING: Turning off rack: Std0009
WARNING: Turning off rack: Std0010
Zwróć uwagę, że liczba stojaków zwiększa się za każdym razem, gdy uruchamiasz ten przykład.
Atrybuty weryfikacji właściwości
Atrybuty weryfikacji umożliwiają przetestowanie wartości podanych dla właściwości spełniających zdefiniowane wymagania. Walidacja jest wyzwalana po przypisaniu wartości. Zobacz about_functions_advanced_parameters.
Przykład użycia atrybutów weryfikacji
class Device {
[ValidateNotNullOrEmpty()][string]$Brand
[ValidateNotNullOrEmpty()][string]$Model
}
[Device]$dev = [Device]::new()
Write-Output "Testing dev"
$dev
$dev.Brand = ""
Testing dev
Brand Model
----- -----
Exception setting "Brand": "The argument is null or empty. Provide an
argument that is not null or empty, and then try the command again."
At C:\tmp\Untitled-5.ps1:11 char:1
+ $dev.Brand = ""
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
Dziedziczenie w klasach programu PowerShell
Klasę można rozszerzyć, tworząc nową klasę pochodzącą z istniejącej klasy. Klasa pochodna dziedziczy właściwości klasy bazowej. Metody i właściwości można dodawać lub zastępować zgodnie z wymaganiami.
Program PowerShell nie obsługuje wielu dziedziczenia. Klasy nie mogą dziedziczyć z więcej niż jednej klasy. W tym celu można jednak używać interfejsów.
Implementacja dziedziczenia jest definiowana przez :
operatora, co oznacza rozszerzenie tej klasy lub zaimplementowanie tych interfejsów. Klasa pochodna powinna zawsze znajdować się w lewej części deklaracji klasy.
Przykład użycia prostej składni dziedziczenia
W tym przykładzie przedstawiono prostą składnię dziedziczenia klas programu PowerShell.
Class Derived : Base {...}
W tym przykładzie przedstawiono dziedziczenie z deklaracją interfejsu przychodzącą po klasie bazowej.
Class Derived : Base.Interface {...}
Przykład prostego dziedziczenia w klasach programu PowerShell
W tym przykładzie klasy Rack i Device używane w poprzednich przykładach są lepiej zdefiniowane, aby: uniknąć powtórzeń właściwości, lepiej dopasować typowe właściwości i ponownie użyć typowej logiki biznesowej.
Większość obiektów w centrum danych to zasoby firmy, co ma sens, aby rozpocząć śledzenie ich jako zasobów. Typy urządzeń są definiowane przez wyliczenie DeviceType
, zobacz about_Enum , aby uzyskać szczegółowe informacje na temat wyliczenia.
W naszym przykładzie definiujemy Rack
tylko rozszerzenia i ComputeServer
; oba rozszerzenia Device
klasy.
enum DeviceType {
Undefined = 0
Compute = 1
Storage = 2
Networking = 4
Communications = 8
Power = 16
Rack = 32
}
class Asset {
[string]$Brand
[string]$Model
}
class Device : Asset {
hidden [DeviceType]$devtype = [DeviceType]::Undefined
[string]$Status
[DeviceType] GetDeviceType(){
return $this.devtype
}
}
class ComputeServer : Device {
hidden [DeviceType]$devtype = [DeviceType]::Compute
[string]$ProcessorIdentifier
[string]$Hostname
}
class Rack : Device {
hidden [DeviceType]$devtype = [DeviceType]::Rack
hidden [int]$Slots = 8
[string]$Datacenter
[string]$Location
[Device[]]$Devices = [Device[]]::new($this.Slots)
Rack (){
## Just create the default rack with 8 slots
}
Rack ([int]$s){
## Add argument validation logic here
$this.Devices = [Device[]]::new($s)
}
[void] AddDevice([Device]$dev, [int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $dev
}
[void] RemoveDevice([int]$slot){
## Add argument validation logic here
$this.Devices[$slot] = $null
}
}
$FirstRack = [Rack]::new(16)
$FirstRack.Status = "Operational"
$FirstRack.Datacenter = "PNW"
$FirstRack.Location = "F03R02.J10"
(0..15).ForEach({
$ComputeServer = [ComputeServer]::new()
$ComputeServer.Brand = "Fabrikam, Inc." ## Inherited from Asset
$ComputeServer.Model = "Fbk5040" ## Inherited from Asset
$ComputeServer.Status = "Installed" ## Inherited from Device
$ComputeServer.ProcessorIdentifier = "x64" ## ComputeServer
$ComputeServer.Hostname = ("r1s" + $_.ToString("000")) ## ComputeServer
$FirstRack.AddDevice($ComputeServer, $_)
})
$FirstRack
$FirstRack.Devices
Datacenter : PNW
Location : F03R02.J10
Devices : {r1s000, r1s001, r1s002, r1s003...}
Status : Operational
Brand :
Model :
ProcessorIdentifier : x64
Hostname : r1s000
Status : Installed
Brand : Fabrikam, Inc.
Model : Fbk5040
ProcessorIdentifier : x64
Hostname : r1s001
Status : Installed
Brand : Fabrikam, Inc.
Model : Fbk5040
<... content truncated here for brevity ...>
ProcessorIdentifier : x64
Hostname : r1s015
Status : Installed
Brand : Fabrikam, Inc.
Model : Fbk5040
Wywoływanie konstruktorów klasy bazowej
Aby wywołać konstruktor klasy bazowej z podklasy, dodaj base
słowo kluczowe.
class Person {
[int]$Age
Person([int]$a)
{
$this.Age = $a
}
}
class Child : Person
{
[string]$School
Child([int]$a, [string]$s ) : base($a) {
$this.School = $s
}
}
[Child]$littleone = [Child]::new(10, "Silver Fir Elementary School")
$littleone.Age
10
Wywoływanie metod klasy bazowej
Aby zastąpić istniejące metody w podklasach, zadeklaruj metody przy użyciu tej samej nazwy i podpisu.
class BaseClass
{
[int]days() {return 1}
}
class ChildClass1 : BaseClass
{
[int]days () {return 2}
}
[ChildClass1]::new().days()
2
Aby wywołać metody klasy bazowej z przesłonięć implementacji, rzutuj do klasy bazowej ([baseclass]$this) przy wywołaniu.
class BaseClass
{
[int]days() {return 1}
}
class ChildClass1 : BaseClass
{
[int]days () {return 2}
[int]basedays() {return ([BaseClass]$this).days()}
}
[ChildClass1]::new().days()
[ChildClass1]::new().basedays()
2
1
Interfejsy
Składnia deklarowania interfejsów jest podobna do języka C#. Interfejsy można zadeklarować po typach podstawowych lub bezpośrednio po dwukropku (:
), gdy nie określono typu podstawowego. Rozdziel wszystkie nazwy typów przecinkami.
class MyComparable : system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
class MyComparableBar : bar, system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
Importowanie klas z modułu programu PowerShell
Import-Module
#requires
i instrukcja importuje tylko funkcje modułu, aliasy i zmienne zdefiniowane przez moduł. Klasy nie są importowane. Instrukcja using module
importuje klasy zdefiniowane w module. Jeśli moduł nie zostanie załadowany w bieżącej sesji, using
instrukcja zakończy się niepowodzeniem.