O třídách
Krátký popis
Popisuje, jak můžete pomocí tříd vytvářet vlastní typy.
Dlouhý popis
PowerShell 5.0 přidá formální syntaxi pro definování tříd a dalších uživatelsky definovaných typů. Přidání tříd umožňuje vývojářům a odborníkům v oblasti IT využívat PowerShell pro širší škálu případů použití. Zjednodušuje vývoj artefaktů PowerShellu a urychluje pokrytí povrchů správy.
Deklarace třídy je podrobný plán, který se používá k vytváření instancí objektů za běhu. Když definujete třídu, název třídy je název typu. Pokud například deklarujete třídu s názvem Device a inicializujete proměnnou $dev
na novou instanci zařízení, $dev
je objekt nebo instance typu Device. Každá instance zařízení může mít různé hodnoty ve vlastnostech.
Podporované scénáře
- Definujte vlastní typy v PowerShellu pomocí známé sémantiky objektově orientovaného programování, jako jsou třídy, vlastnosti, metody, dědičnost atd.
- Ladění typů pomocí jazyka PowerShellu
- Generování a zpracování výjimek pomocí formálních mechanismů
- Definujte prostředky DSC a jejich přidružené typy pomocí jazyka PowerShellu.
Syntax
Třídy jsou deklarovány pomocí následující syntaxe:
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> ...]
}
Třídy se vytvářejí pomocí některé z následujících syntaxí:
[$<variable-name> =] New-Object -TypeName <class-name> [
[-ArgumentList] <constructor-argument-list>]
[$<variable-name> =] [<class-name>]::new([<constructor-argument-list>])
Poznámka
Při použití [<class-name>]::new(
syntaxe jsou závorky kolem názvu třídy povinné. Závorky signalizují definici typu pro PowerShell.
Příklad syntaxe a použití
Tento příklad ukazuje minimální syntaxi potřebnou k vytvoření použitelné třídy.
class Device {
[string]$Brand
}
$dev = [Device]::new()
$dev.Brand = "Microsoft"
$dev
Brand
-----
Microsoft
Vlastnosti třídy
Vlastnosti jsou proměnné deklarované v oboru třídy. Vlastnost může být libovolného předdefinovaný typ nebo instance jiné třídy. Třídy nemají žádné omezení počtu vlastností, které mají.
Příklad třídy s jednoduchými vlastnostmi
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
Příklady složitých typů ve vlastnostech třídy
Tento příklad definuje prázdnou třídu racku pomocí třídy Device . Následující příklady ukazují, jak přidat zařízení do racku a jak začít s předpřipraveným rackem.
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 tříd
Metody definují akce, které mohou třídy provádět. Metody mohou přijímat parametry, které poskytují vstupní data. Metody mohou vracet výstup. Data vrácená metodou mohou být libovolným definovaným datovým typem.
Příklad jednoduché třídy s vlastnostmi a metodami
Rozšíření třídy Rack pro přidání a odebrání zařízení do nebo z ní.
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
Výstup v metodách tříd
Metody by měly mít definovaný návratový typ. Pokud metoda nevrací výstup, měl by být [void]
typ výstupu .
V metodách třídy se do kanálu neposílají žádné objekty kromě objektů uvedených v return
příkazu. Z kódu neexistuje žádný náhodný výstup kanálu.
Poznámka
To se v podstatě liší od toho, jak funkce PowerShellu zpracovávají výstup, kde všechno směřuje do kanálu.
Výstup metody
Tento příklad ukazuje žádný náhodný výstup kanálu z metod třídy, s výjimkou příkazu 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žňují nastavit výchozí hodnoty a ověřit logiku objektu v okamžiku vytvoření instance třídy. Konstruktory mají stejný název jako třída. Konstruktory můžou mít argumenty pro inicializaci datových členů nového objektu.
Třída může mít definované nulové nebo více konstruktorů. Pokud není definován žádný konstruktor, třída má výchozí konstruktor bez parametrů. Tento konstruktor inicializuje všechny členy na výchozí hodnoty. Typy objektů a řetězce mají hodnoty null. Při definování konstruktoru se nevytvořil žádný výchozí konstruktor bez parametrů. Pokud je potřeba, vytvořte konstruktor bez parametrů.
Základní syntaxe konstruktoru
V tomto příkladu je třída Device definována s vlastnostmi a konstruktorem. Chcete-li použít tuto třídu, je uživatel vyžadován k zadání hodnot parametrů uvedených v konstruktoru.
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
Příklad s více konstruktory
V tomto příkladu je třída Device definována s vlastnostmi, výchozím konstruktorem a konstruktorem pro inicializaci instance.
Výchozí konstruktor nastaví značku na Hodnotu Undefined a ponechá model a skladovou položku dodavatele s hodnotami 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
Skrytý atribut
Atribut hidden
zviditelní vlastnost nebo metodu. Vlastnost nebo metoda je stále přístupná uživateli a je k dispozici ve všech oborech, ve kterých je objekt k dispozici. Skryté členy jsou z Get-Member
rutiny skryté a nelze je zobrazit pomocí dokončování tabulátoru nebo IntelliSense mimo definici třídy.
Příklad použití skrytých atributů
Při vytvoření objektu Rack je počet slotů pro zařízení pevnou hodnotou, která by se neměla kdykoli změnit. Tato hodnota je známa při vytváření.
Použití skrytého atributu umožňuje vývojáři zachovat počet slotů skrytých a zabránit neúmyslným změnám velikosti racku.
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
Všimněte si , že vlastnost Sloty se ve výstupu nezobrazuje $r1
. Velikost však změnil konstruktor.
Statický atribut
Atribut static
definuje vlastnost nebo metodu, která existuje ve třídě a nepotřebuje žádnou instanci.
Statická vlastnost je vždy dostupná, nezávisle na instanci třídy. Statická vlastnost se sdílí ve všech instancích třídy. Statická metoda je k dispozici vždy. Všechny statické vlastnosti jsou aktivní pro celý rozsah relace.
Příklad použití statických atributů a metod
Předpokládejme, že v datovém centru existují instance racků. Proto byste chtěli sledovat racky ve vašem kódu.
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))
}
}
}
Testování statické vlastnosti a metody existují
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
Všimněte si, že počet racků se při každém spuštění tohoto příkladu zvyšuje.
Atributy ověření vlastnosti
Ověřovací atributy umožňují testovat, že hodnoty zadané vlastnostmi splňují definované požadavky. Ověření se aktivuje v okamžiku, kdy je hodnota přiřazena. Viz about_functions_advanced_parameters.
Příklad použití ověřovacích atributů
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
Dědičnost v třídách PowerShellu
Třídu můžete rozšířit vytvořením nové třídy, která je odvozena od existující třídy. Odvozená třída dědí vlastnosti základní třídy. Podle potřeby můžete přidat nebo přepsat metody a vlastnosti.
PowerShell nepodporuje více dědičnosti. Třídy nemohou dědit z více než jedné třídy. Pro tento účel však můžete používat rozhraní.
Implementace dědičnosti je definována operátorem :
; to znamená rozšířit tuto třídu nebo implementovat tato rozhraní. Odvozená třída by měla být vždy vlevo v deklaraci třídy.
Příklad použití jednoduché syntaxe dědičnosti
Tento příklad ukazuje jednoduchou syntaxi dědičnosti tříd PowerShellu.
Class Derived : Base {...}
Tento příklad ukazuje dědičnost pomocí deklarace rozhraní přicházející po základní třídě.
Class Derived : Base.Interface {...}
Příklad jednoduché dědičnosti v třídách PowerShellu
V tomto příkladu jsou třídy racku a zařízení použité v předchozích příkladech lépe definovány tak, aby se zabránilo opakování vlastností, lepší sladění běžných vlastností a opakované použití běžné obchodní logiky.
Většina objektů v datovém centru je firemní aktiva, která dává smysl začít je sledovat jako aktiva. Typy zařízení jsou definovány výčtem DeviceType
, viz about_Enum podrobnosti o výčtech.
V našem příkladu definujeme Rack
pouze rozšíření třídy a ComputeServer
obě rozšíření třídy Device
.
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
Volání konstruktorů základní třídy
Pokud chcete vyvolat konstruktor základní třídy z podtřídy, přidejte klíčové base
slovo.
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
Vyvolání metod základní třídy
Chcete-li přepsat existující metody v podtřídách, deklarujte metody pomocí stejného názvu a podpisu.
class BaseClass
{
[int]days() {return 1}
}
class ChildClass1 : BaseClass
{
[int]days () {return 2}
}
[ChildClass1]::new().days()
2
Chcete-li volat metody základní třídy z přepsáných implementací, přetypujte na základní třídu ([baseclass]$this) při vyvolání.
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
Rozhraní
Syntaxe pro deklarování rozhraní je podobná jazyku C#. Rozhraní můžete deklarovat po základních typech nebo bezprostředně za dvojtečku (:
), pokud není zadán žádný základní typ. Všechny názvy typů oddělte čárkami.
class MyComparable : system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
class MyComparableBar : bar, system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
Import tříd z modulu PowerShellu
Import-Module
#requires
a příkaz importuje pouze funkce modulu, aliasy a proměnné, jak je definováno modulem. Třídy se neimportují. Příkaz using module
importuje třídy definované v modulu. Pokud se modul nenačte v aktuální relaci, using
příkaz selže.