PowerShell Klassen: Aan de slag

PowerShell is een objectgeoriënteerde taal. Wanneer je commando’s uitvoert, zie je de uitvoer op je scherm, dat zijn objecten. Objecten komen niet zomaar uit de lucht vallen; ontwikkelaars creëren ze of, meer specifiek, instantiëren ze met klassen. PowerShell-klassen vertegenwoordigen definities of schema’s van die objecten.

Hoewel je misschien bekend bent met het maken van objecten met commando’s zoals New-Object en het gebruik van de pscustomobject type accelerator, zijn dit geen “nieuwe” objecten. Het soort objecten dat deze methoden produceren, is van een specifiek type. PowerShell-klassen definiëren het type.

In deze tutorial ga je leren hoe je aan de slag kunt met PowerShell-klassen. Je zult je eerste klas maken met constructors, leren hoe je objecten maakt vanuit je klas, en je klas uitbreiden met eigenschappen en methoden.

Voor achtergrondinformatie over termen zoals objecten, eigenschappen en methoden, bekijk de blogpost Terug naar de basis: PowerShell-objecten begrijpen.

Vereisten

Het maken van Je Eerste Klas en Object

Voordat je de ins en outs van een PowerShell-klasse kunt leren, moet je eerst een eenvoudige klasse maken. De meer geavanceerde onderwerpen leer je later.

Het maken van je eerste klasse zal een beetje voelen als het maken van een functie. De basis syntaxis is hetzelfde. Een klasse wordt gemaakt vanuit een definitie, net als een functie. In tegenstelling tot functies begint de eerste regel echter niet met function gevolgd door de naam van de functie, maar begint met class gevolgd door de naam van het objecttype.

Hieronder zie je het kale skelet van een klasse genaamd student.

class student {

}

Klassen hebben eigenschappen die lijken op parameters die attributen zijn die die klasse beschrijven. Het onderstaande voorbeeld toont een klasse genaamd student met twee eigenschappen; FirstName en LastName.

Wanneer je een eigenschap definieert, moet je altijd een type definiëren dat een specifiek “schema” instelt voor wat eigenschapswaarden kunnen bevatten. In het onderstaande voorbeeld worden beide eigenschappen gedefinieerd als strings.

Je moet altijd eigenschapstypes definiëren. Je zult later zien waarom.

class student {
    [string]$FirstName
    [string]$LastName
}

Na het definiëren van een klasse, maak je een object ervan of instantieer je een object. Er zijn meerdere manieren om objecten te instantiëren vanuit klassen; een veelvoorkomende manier is het gebruik van type accelerators zoals [student] die de klasse vertegenwoordigen, gevolgd door een standaard methode die bij elke klasse wordt geleverd, genaamd new().

Het gebruik van de type accelerator snelkoppeling is hetzelfde als het maken van een object met behulp van de New-Object-opdracht.

New-Object -TypeName student

Eenmaal je een object hebt gemaakt van die klasse, wijs dan waarden toe aan de eigenschappen. Het onderstaande voorbeeld wijst waarden toe aan Tyler en Muir voor de eigenschappen FirstName en LastName.

class student {
    [string]$FirstName
    [string]$LastName
}
$student1 = [student]::new()
$student1.FirstName = 'Tyler'
$student1.LastName = 'Muir'
$student1

Als je het object hebt gemaakt en waarden hebt toegewezen aan de eigenschappen, inspecteer dan het object door de variabele te noemen waaraan je het object hebt toegewezen, zoals hieronder wordt getoond.

Creating an object from the student class.

Nu je een object hebt gemaakt van een klasse, leid dat object net als elk ander object in PowerShell door naar de Get-Member-cmdlet om het te inspecteren. Je kunt hieronder zien dat het object in de variabele $student1 van het type student is.

De klassenaam komt altijd overeen met het objecttype.

Merk op dat Get-Member vier methoden en twee eigenschappen retourneert. De eigenschappen zien er waarschijnlijk bekend uit, maar de methoden waarschijnlijk niet. PowerShell voegt standaard bepaalde methoden toe, maar je kunt je eigen methoden toevoegen of zelfs de standaardmethoden wijzigen.

Showing members from custom student object.

Methoden maken

In het bovenstaande voorbeeld zag je een paar standaardmethoden op het object, maar waarschijnlijk wil je je eigen methoden maken. Om dat te doen, moet je een of meer methoden definiëren binnen de klassedefinitie.

A method definition looks like below with an output type that defines what type of object is returned from this method, the name of the method, and the code to execute inside of a scriptblock.

[<output type>]<name>() {
	<code that runs when the method is executed>
}

Let op de haakjes () na de naam. Hier kun je methodenparameters definiëren (later behandeld). Methodenparameters stellen je in staat om de functionaliteit van een methode te wijzigen, net zoals je dat kunt doen met functieparameters.

Als je eerder PowerShell-functies hebt geschreven en uitgevoerd, zouden scriptblokken als methoden bekend moeten voelen, maar er zijn een paar speciale regels voor methoden die je moet kennen.

return is verplicht

PowerShell-functies zullen objecten retourneren door eenvoudigweg het object ergens in de functie te plaatsen zoals in het onderstaande voorbeeld.

function foo {
	$object = Get-Service
	$object ## Het object gewoon naar de pijplijn sturen
}

Anders dan bij functies, als een methode een object retourneert, moet je de return-constructie gebruiken zoals hieronder getoond.

[string]GetName() {
	return 'foo'
}

Het gebruik van de $this-variabele

Nog een verschil tussen methoden en functies is de $this-variabele. De $this-variabele, zoals gedefinieerd binnen een methode, verwijst naar de eigenschappen of andere methoden van het huidige object.

Hieronder staat een voorbeeld van een methode genaamd GetName() toegevoegd aan de klasse student die de waarde van de eigenschappen FirstName en LastName concateneert en retourneert.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
}

Nu kun je de GetName()-methode oproepen met behulp van de puntnotatie zoals hieronder getoond. Als je eerder waarden hebt toegewezen aan FirstName en LastName, zal GetName() ze retourneren.

Creating a class with a method and showing to output.

Parameters toevoegen aan Methoden

In het bovenstaande voorbeeld, toen je de regel $student1.GetName() uitvoerde, riep je de GetName()-methode aan zoals die is. Binnen de haakjes kun je parameters definiëren net als bij functies.

De methode GetName() gaf gewoon de waarden terug die waren ingesteld voor de eigenschappen FirstName en LastName. Maar wat als je liever een methode hebt om eigenschappen in te stellen die GetName() vervolgens kan ophalen? In dat geval moet je method parameters definiëren.

Definieer method parameters door een of meer parameters gescheiden door een komma op te nemen tussen de haakjes van de methodeparameter, zoals hieronder wordt getoond.

Merk op het outputtype [void]. Telkens wanneer een methode niets uitvoert, heb je geen return-constructie nodig, en je moet het outputtype definiëren als [void] om PowerShell te vertellen dat de methode niets teruggeeft.

[void]SetName([string]$Name) {

}

Bijvoorbeeld, misschien accepteert de methode SetName() een volledige naam (voornaam en achternaam). Als dat het geval is, kun je in het scriptblok deze string splitsen en de voornaam en achternaam op die manier toewijzen.

Door de methode SetName() in de klasse student in te voegen, ziet het er nu zo uit.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

Nu kun je een volledige naam als parameter doorgeven aan de methode SetName(), die de eigenschappen FirstName en LastName van het huidige object instelt.

Creating a class with a void method and showing the output when it is run.

Methoden Overbelasten

Misschien wil je verschillende parameter sets definiëren voor een methode. Net zoals bij parameter sets werken in functies en cmdlets, kun je verschillende parameter “contexten” of method signatures definiëren.

Misschien wilt u de parameters FirstName en LastName instellen door een volledige naam door te geven aan de SetName()-methode of door de voornaam en achternaam apart door te geven. U hoeft niet te kiezen; u kunt ze allebei definiëren met methodesignaturen.

Wanneer u meer dan één methodesignaturen definieert in een klasse, wordt dat overbelasting genoemd.

Door het voorbeeld uit de vorige sectie opnieuw te gebruiken, kunt u een overbelasting maken voor de SetName()-methode om twee strings in plaats van één te accepteren. Wanneer u twee strings doorgeeft in plaats van één, neemt de SetName()-methode aan dat de eerste string de FirstName is en de tweede string de LastName is. Met die overbelasting zou de klasse er als volgt uitzien.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
    
    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}
Showing that the method overload works by providing either one or two strings.

Klasseconstructoren

Telkens wanneer u een object instancieert met de new()-methode of op een andere manier, kunt u PowerShell vertellen om wat door de gebruiker gedefinieerde code genaamd een constructor uit te voeren. Constructoren zijn als methoden, maar ze worden automatisch uitgevoerd wanneer PowerShell een object instantieert.

Elke klasse heeft een standaardconstructor. Deze standaardconstructor doet niet veel; hij is alleen verantwoordelijk voor het instantiëren van het object. U kunt de standaardconstructor zien door de uitvoer van de New-methode te bekijken. U kunt hieronder zien dat deze regel een enkele new()-methode retourneert.

[student]::New
Default PowerShell constructor

Constructor Overbelasting

Misschien wil je een waarde instellen voor de FirstName en LastName eigenschappen zodra je het object creëert, niet met de typische punt notatie. In dat geval kun je een constructor maken met een parameter die vervolgens SetName() aanroept.

Hieronder staat een voorbeeld van een constructor voor de student klasse. Let op dat de constructor geen specifieke naam heeft of wordt voorafgegaan door een uitvoertype. Constructors gebruiken altijd dezelfde naam als de klasse.

Het aanroepen van een bestaande methode in de constructor stelt ons in staat om de methode die we al hebben geschreven om de variabelen in te stellen opnieuw te gebruiken.

student([string]$Name) {
	$this.SetName($Name)
}

En hieronder zie je die constructor toegevoegd aan de student klasse.

class student {
    [string]$FirstName
    [string]$LastName
    
    student([string]$Name) {
        $this.SetName($Name)
    }

    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

Wanneer je een nieuw student object instantieert en een string parameter doorgeeft, zullen de objecteigenschappen onmiddellijk de verwachte waarden hebben.

Showing the output from using the constructor with a string

Je kunt nu de overloaded constructor weer zien met [student]::New. Let nu op dat de nieuwe overloaded constructor gedefinieerd is met een Name parameter.

Overloaded constructor

Het Definiëren van een Standaard- en Overloaded Constructor

Nu je een overloaded constructor hebt in je student klasse, overschrijft PowerShell de standaardconstructor. Maar je kunt deze terugkrijgen door er handmatig een zonder parameters aan te maken.

student() {}

Je kunt zien hoe dat eruitziet in de student klasse hieronder.

class student {
    [string]$FirstName
    [string]$LastName

    student([string]$Name) {
        $this.SetName($Name)
    }

    student() {}

    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

Controleer nu opnieuw de constructors. Je zult nu zien dat beide constructors verschijnen.

[student]::New
Creating a default and custom constructor

Klasse Overerving

Zoals alle andere objectgeoriënteerde talen, kun je PowerShell-klassen hiërarchisch opbouwen met meerdere klassen. Elke klas kan “ouder” en “kind” klassen hebben die beginnen met minder specifieke, meer generieke doeleinden en specificiteit verhogen.

Bijvoorbeeld, onze student-klasse vertegenwoordigt een universiteitsstudent (kind/specifiek). Die universiteitsstudent is een persoon (ouder/generiek). Deze twee concepten zijn gerelateerd en vormen een hiërarchie.

A child class can inherit a parent class which means it can hold all properties and methods (members) defined via a parent class. We know that a person class may have properties like eye_color, height, and weight and perhaps a method called SetHeight().

Als een student een persoon is, heeft die student nog steeds dezelfde eigenschappen en methoden. Het zou dubbel werk zijn om dezelfde leden op de student-klasse te implementeren die de persoon-klasse al heeft. Je kunt klassikale overerving definiëren om automatisch alle leden van de persoon-klasse op de student-klasse te definiëren.

Als dit nu geen zin heeft, zal het dat wel doen terwijl we een demonstratie doornemen.

Demonstratie van Klassenovererving

Ten eerste, maak een kopie van de student-klasse die je eerder hebt gemaakt, verwijder de constructors en hernoem deze naar een persoon-klasse. Jouw persoon-klasse zou er als volgt uit moeten zien.

A student, of course, has a first name and last name, but the class can be described more accurately by labeling it as a person. When creating a more “generic” class like this, you can create more specific “child” classes from it.

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

Maak nu een paar klassen die een persoon vertegenwoordigen maar een meer specifieke rol hebben. Bijvoorbeeld, in het onderstaande codefragment heb je nu een leraar– en student-klasse.

class teacher {
    [int]$EmployeeId
}

class student {
    [int]$StudentId
}

Zoals ze nu zijn, zijn de leraar– en student-klasse onderling exclusief van de persoon-klasse. Ze hebben geen relatie maar kunnen geen klassenleden van de persoon-klasse erven. Laten we dat veranderen.

Nu definieer die hiërargie deur die teacher en student klas as “kind” klasse van die persoon klas met erfenis te definieer. Jy kan erfopvolging definieer deur ’n kolon (:) agter die klasnaam te plaas, gevolg deur die naam van die ouerklassse soos hieronder getoon.

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

Jou hele klas skrip moet nou so lyk:

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

Op hierdie punt, wanneer jy ’n objek instansieer van die teacher of student klas, sal beide klasse dieselfde lede as die persoon klas hê.

Class Inheritance Demo

Erfenis met Konstruksies

Soos jy hierbo gesien het, word klasmetodes geërf deur klaserfenis. Hierdie gedrag mag jou laat dink dat konstrukteurs dieselfde logika sal volg, maar jy sou verkeerd wees. Konstrukteurs word nie geërf nie, en konstrukteurs vir alle kindklasse moet afsonderlik in elke kindklasse gedefinieer word.

Byvoorbeeld, dalk het jy net ’n oorlade konstrukteur vir die persoon klas gedefinieer, maar het nie ’n konstrukteur vir die teacher klas gedefinieer nie, soos hieronder getoon.

class person {
    [string]hidden $FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }

		person([string]$Name) {
			$this.SetName($Name)
		}
}

Jy definieer dan ’n kindklas, teacher, byvoorbeeld, en probeer om ’n objek sonder parameters daarvan te skep, soos hieronder getoon. Let daarop dat PowerShell ’n fout teruggee omdat ’n parameterlose konstrukteur nie binne die teacher klas gedefinieer is nie.

No class defined for child class

A constructor is not necessary in a child class if you’re only using it as a template. Alternatively, if you want to use the parent class as its own standalone class and as a parent class you can include constructors. But you have to make sure that the parent class has a constructor that matches the ones in the child classes.

Klaslede-eienskappe

Net soos PowerShell-opdragparameters, kan klasse lede-eienskappe hê. Hierdie eienskappe wysig die gedrag van elke lid.

Versteekte Lede

Als u een klasse-lid alleen voor interne doeleinden gebruikt en niet wilt dat de gebruiker erin leest of ernaar schrijft, stelt u een lid in als verborgen. Bijvoorbeeld, misschien heeft u een methode die alleen door andere methoden wordt gebruikt. Er is geen noodzaak om die methode bloot te stellen aan de gebruiker.

Om een verborgen lid te definiëren, gebruikt u het hidden attribuut zoals hieronder weergegeven.

class teacher {
    [int]hidden $EmployeeId
}

Als u nu Get-Member gebruikt om alle objectleden te inspecteren, wordt die eigenschap niet weergegeven.

Class Member Attributes

Het instellen van een klasse-lid als verborgen beperkt de toegang tot de waarde niet; het verbergt het alleen uit het zicht. U moet eigenschappen niet verbergen om gevoelige gegevens op te slaan.

Statische leden

Herinner u eerder; deze tutorial gebruikte de term “instantiëren” om het maken van een object uit een klasse te beschrijven. Wanneer u een object instantieert, neemt dat object alle eigenschappen en methoden over die de klasse definieert. Maar dat is niet altijd het geval.

Soms heeft u niet de overhead van het instantiëren van een heel object nodig. In plaats daarvan moet u snel naar een enkel klasse-lid verwijzen. In dat geval kunt u een klasse-lid instellen als statisch.

Net als bij het hidden attribuut, definieert u een klasse-lid als statisch met behulp van het static trefwoord zoals hieronder weergegeven.

class student {
	[int]static $MaxClassCount = 7
}

In tegenstelling tot typische klasse-leden, maakt PowerShell geen eigenschappen en methoden van statische klasse-leden. Wanneer u een klasse-lid als statisch definieert, zoals verborgen leden, wordt het niet weergegeven wanneer u Get-Member gebruikt.

Static Members

Bijvoorbeeld, misschien wil je universiteitsvakken associëren met de student-klasse en het maximale aantal universiteitsvakken definiëren waarin een student kan deelnemen. Om dat te doen, maak je een Classes-array-lid en een MaxClassCount-lid aan.

Aangezien de gebruiker zelden het MaxClassCount-lid hoeft te wijzigen, besluit je om het als statisch te definiëren.

Tenslotte maak je een AddClass()-methode aan om een vak aan het rooster van de student toe te voegen, maar alleen als het minder is dan dat MaxClassCount.

class student {
    [string[]]$Classes = @()
    [int]static $MaxClassCount = 7
    
    [void]AddClass ([string]$Name) {
        if ($this.Classes.Count -lt [student]::MaxClassCount) {
            $this.Classes += $Name
        }
    }
}

Nu, wanneer je probeert een nieuw student-object te maken en te veel universiteitsvakken eraan toe te wijzen, zal PowerShell alleen het maximale aantal toewijzen, wat zeven zou zijn.

$student1 = [student]::new()
'PE','English','Math','History','Computer Science','French','Wood Working','Cooking' | ForEach-Object {
	$student1.AddClass($_)
}
$student1.Classes
Class Count

Je kunt de waarden van statische leden op elk moment wijzigen. Als je bijvoorbeeld het MaxClassCount-lid 5 in plaats van 7 wilt maken, zou je de waarde veranderen met [student]::MaxClassCount = 5. Het veranderen van de waarde zou in dit voorbeeld geen klassen retroactief verwijderen die het limiet overschrijden.

Conclusie

PowerShell-klassen vervagen de grens tussen een scripttaal en een programmeertaal. Klassen zijn een geweldige manier om objectrelaties te definiëren, manieren toe te voegen om met objecten te communiceren en ze op te maken, wat normaal gesproken alleen mogelijk zou zijn door gespecialiseerde functies te schrijven.

Source:
https://adamtheautomator.com/powershell-classes/