Osztályok (class )

Az előző fejezetben láttuk az új típusok létrehozásának egy módszerét. A nehézség az volt, hogy C#-ban kellett megadni a definíciót, ami nem biztos, hogy mindenkinek egyszerűen megy. PowerShell 5.0-tól jelent meg az az új lehetőség, hogy PowerShell szintaxissal hozhatunk létre új típusokat.

Osztály létrehozása és példányosítása

Ezzel az új lehetőséggel tehát nem csak PSObject típusú egyedi objektumokat hozhatunk létre, hanem teljesen új típust definiálva hozhatjuk létre egyedi objektumainkat, C# forráskód használata nélkül, natívan PowerShell segítségével. Ráadásul rendelkezésünkre áll az öröklődés és a metódusok újradefiniálása (overload).

Nézzük mindezt néhány egyszerű példán! Szeretnénk szabályos síkidomokat kezelni PowerShellben. A szabályos síkidomok esetében leggyakrabban 2 paramétert kell megadni, gondoljunk a téglalapra, ellipszisre, vagy akár deltoidra. Elsőként ábrázoljuk ezt a közös jellegzetességet egy osztályban, amit nevezzük szabályos síkidomnak:

class SzabályosSíkidom {

    [double] $a = 1

    [double] $b = 1

 

    SzabályosSíkidom ([double] $ai, [double] $bi) {

        $this.a = $ai

        $this.b = $bi

    }

 

    SzabályosSíkidom () {

    }

 

    [String] ToString () {

        return "a:$($this.a) b:$($this.b)"

    }

}

 A típus, vagy más szóval osztály definiálására a class kulcsszó áll rendelkezésünkre. Ezután kell szerepeltetni a típus, osztály nevét, majd kapcsos zárójelek között jön az osztály definíciója. Ez áll tulajdonságokból, amelyeket mint változókat rakunk bele. És áll metódusokból, amelyek különösebb kulcsszó nélkül állnak, de fontos, hogy a metódus neve mögött ott kell állnia a gömbölyű zárójel-párnak.

A szabályos síkidomokra, ahogy korábban említettem, általánosan jellemző, hogy két adatot kell megadni velük kapcsolatban, ezek lettek az ’a’ és ’b’ tulajdonság. Amit láthatunk, hogy kötelező a tulajdonságok típusát jelölni, mindkettő [double] típusú és mindkettőnek 1 itt most az alaphelyzet szerinti értéke. A tulajdonságok nyilvánosak, azaz „kívülről” hozzáférhetők, értékük kiolvasható és át is írható.

Az osztálydefinícióban metódusokat is létrehozhatunk. Elsőként nézzük a legalsó, ToString metódust! Itt látható, hogy kötelező a metódusok visszatérési értékének típusát jelölni, ami itt [string]. Valamint kötelező szerepeltetni a return kulcsszót a kimenet jelzésére. Ha a metódusokban hivatkozni szeretnénk a tulajdonságokra, akkor nem $a és $b-vel tehetjük ezt meg, hanem $this.a és $this.b formában, ahol $this az osztály példányát magát szimbolizálja.

A fenti példában láthatunk még két ugyanolyan metódust, amelyeknek a neve megegyezik az osztály nevével. Ezek az osztály konstruktorai. A konstruktor egy speciális metódus, ami akkor hívódik meg, amikor az osztály egy új példányát hozzuk létre. A konstruktor neve tehát kötelezően megegyezik az osztály nevével, és itt nem kell jelezni a visszatérési érték típusát, hiszen pont az osztály egy példányát fogja visszaadni, és a return kulcsszót sem kell szerepeltetni, implicit módon a ’return $this’ kifejezést képzelhetjük oda.

Látható tehát, hogy ugyanazzal a névvel több metódusunk, akár konstruktorunk is lehet. Ezeknek valamilyen paraméterben el kell térniük egymástól. Az első konstruktorom két [double] típusú paramétert vár, a második meg semmit, így ezek egymástól különbözővé teszik a két konstruktort.

Ha lefuttatjuk a fenti típusdefiníciót, akkor az alábbi két módon is hozhatok létre példányt, azaz futtathatom a konstruktort. Hogy éppen melyiket használom a több lehetőség közül, azt a paraméterek döntik el:

PS C:\> $idom1 = New-Object -TypeName SzabályosSíkidom -ArgumentList 5,6

PS C:\> $idom1

a b

- -

5 6

 

PS C:\> $idom2 = [szabályossíkidom]::new()

PS C:\> $idom2

a b

- -

1 1

Az első esetben a New-Object-et használtam a példány létrehozására. Itt az első konstruktort használtam, hiszen két számot adtam át paraméterként. Ugyan nem közvetlenül [double] típusúakat, de a használt [int]-eket a PowerShell könnyedén át tudta lebegőpontos számokká alakítani.

Ha egy osztálynak nincs konstruktora, akkor is implicit módon van. Ha ezt az osztályt definiáljuk:

class Egyszerű {

    [int] $a

}

Akkor ennek a statikus metódusai között ott látjuk a new()konstruktort:

PS C:\> [egyszerű] | Get-Member -Static

 

 

   TypeName: Egyszerű

 

Name            MemberType Definition                                                        

----            ---------- ----------                                                        

Equals          Method     static bool Equals(System.Object objA, System.Object objB)        

new             Method     Egyszerű new()                                                    

ReferenceEquals Method     static bool ReferenceEquals(System.Object objA, System.Object objB)

Öröklődés

Az igazi előnye az osztályok használatának, hogy ha egy meglévőhöz hasonló tudású osztályt akarok létrehozni, akkor nem kell „nulláról” kezdeni, hanem a meglevőből öröklődéssel hozhatom létre az újat, ami az eredetihez képest valamit másképp vagy valamivel többet tud.

Nézzük a téglalapot, mint az előző általános szabályos síkidomból képzett új osztályt:

class Téglalap : SzabályosSíkidom {

    Téglalap () : Base (){

    }

 

    Téglalap ([double] $a, [double] $b) : Base ($a, $b) {

    }

 

    [double] Terület (){

        return $this.a * $this.b

    }

}

Az öröklődést az osztály neve melletti kettőspont utáni alap osztály nevével jelezzük. Ha az új osztály konstruktora ugyanaz, mint az eredeti osztályé, akkor csak egyszerűen jelezzük kettőspont után, hogy az eredeti konstruktort akarjuk meghívni a Base  névvel. Például ez a részlet:

    Téglalap () : Base (){

    }

Ez annyit jelent, hogy a Téglalap konstruktoraként meghívjuk a SzabályosSíkidom konstruktorát, és az ottaniakhoz képest nem kell semmi mást csinálni, így üresen hagytam a metódus törzsét. Ez eredeti osztályhoz képest itt már tudunk területet számolni, így készítettem egy Terület metódust.

Nézzük, hogy egy téglalap példány milyen tagjellemzőkkel bír:

PS C:\> $téglalap = [téglalap]::new(12,3)

 

PS C:\> $téglalap | gm

 

 

   TypeName: Téglalap

 

Name        MemberType Definition                   

----        ---------- ----------                   

Equals      Method     bool Equals(System.Object obj)

GetHashCode Method     int GetHashCode()            

GetType     Method     type GetType()               

Terület     Method     double Terület()             

ToString    Method     string ToString()            

a           Property   double a {get;set;}          

b           Property   double b {get;set;}          

Látható, hogy az újonnan létrehozott Terület mellett ott van az öröklött ToString is, ami jól működik téglalappal is:

PS C:\> $téglalap.ToString()

a:12 b:3

 A Get-Member kimenetén látható, hogy „gyárilag” van Equals metódusunk is, ami mindig False értéket ad, de inkább adjunk neki értelmet akár már a SzabályosSíkidom szintjén:

     [bool] Equals ([object] $object){

        return ($this.a -eq $object.a -and $this.b -eq $object.b)

     }   

 Azaz akkor adunk True-t vissza, ha az a-k és a b-k is egyenlők. Ezzel tényleg összehasonlíthatóvá válik két egyforma téglalap:

PS C:\> $t1 = [téglalap]::new(2,5)

 

PS C:\> $t2 = [téglalap]::new(2,5)

 

PS C:\> $t1 -eq $t2

True

 Van még egy lehetőségünk az osztályokkal kapcsolatban. Tegyük fel, hogy a síkidom nevét is szeretnénk tárolni:

class Téglalap : SzabályosSíkidom {

    hidden [string] $név = "Téglalap"

    Téglalap () : Base (){

    }

 

    Téglalap ([double] $a, [double] $b) : Base ($a, $b) {

    }

 

    [double] Terület (){

        return $this.a * $this.b

    }

}

Látható, hogy felvettem egy új $név tulajdonságot, amihez az új hidden  kulcsszót használtam.

PS C:\> $tgllp = [téglalap]::new(4,7)

 

 

PS C:\> $tgllp

 

a b

- -

4 7

Idáig semmi különleges nem történt. Látszólag nincsen név tulajdonságunk, de ha explicit rákérdezünk, akkor azért kiderül, hogy van:

PS C:\> $tgllp.név

Téglalap

Ez azonban nem látható sem format-list, sem get-member-el:

PS C:\> $tgllp | fl *

 

a : 4

b : 7

 

PS C:\> $tgllp | gm

 

 

   TypeName: Téglalap

 

Name        MemberType Definition                      

----        ---------- ----------                      

Equals      Method     bool Equals(System.Object object)

GetHashCode Method     int GetHashCode()               

GetType     Method     type GetType()                  

Terület     Method     double Terület()                

ToString    Method     string ToString()               

a           Property   double a {get;set;}             

b           Property   double b {get;set;}             

Sajnos jelenleg még nem tudjuk ezt csak olvashatóvá tenni, azaz felül is tudjuk bírálni, bár ha valaki nem tud ennek a tulajdonságnak a létezéséről, akkor ennek esélye kicsi:

PS C:\> $tgllp.név = "amőba"

 

PS C:\> $tgllp.név

amőba

Valószínű ezen a területen sok fejlesztés lesz várható a következő verziókban.

Felsorolás osztály létrehozása

Új lehetőség szintén PowerShell 5.0-tól kezdve, hogy egyéni felsorolás-típusokat már beépítetten támogatja a nyelv, nincs szükség C# kód beágyazására. Nézzünk egy egyszerű felsorolást:

enum Színek {

    Kék = 1

    Zöld = 2

    Sárga = 3

    Piros = 4

    Barna = 5

    Fehér = 6

    Fekete = 7

}

A felsorolás osztály létrehozásához az enum  kulcsszót kell használnunk, majd az osztály nevét és ezután szkriptblokkban meg kell adni – hasonlóan a hashtáblákhoz – a címke-érték párokat. Ezután haszáljuk ezt:

PS C:\> $szín = [színek]::Fekete

PS C:\> $szín

Fekete

PS C:\> [int] $szín

7

Látszik, hogy minden színhez egy szám tartozik.

Van egy másik fajtája is a felsorolás típusnak, ahol nem egy-egy szám feleltethető meg a felsorolás címkéihez, hanem egy-egy bit. Ez azért jó, mert nem csak egy-egy címkét vehet fel a változó értéke, hanem címkék különböző kombinációját is. Ez a Flags  típusú felsorolás, nézzünk erre is egy példát:

[Flags()] enum Bitjeim {

    Egy = 1

    Kettő = 2

    Négy = 4

    Nyolc = 8

    Tizehat = 16

}

Itt az értékek 1-1 helyiértéknek feleltethetők meg a 2-es számrendszerben, így akár egyszerre többet is megadhatunk:

PS C:\> $b = [Bitjeim] "Egy, Kettő"

PS C:\> $b

Egy, Kettő

PS C:\> [int] $b

3

Látható, hogy egy ilyan sztringet használtam értékadásnál, amiben vesszővel választottam el az értékeket, és a [Bitjeim] típuskonverzió ezt a formátumot ügyesen felismerte és a mögöttes szám a bebillentett biteknek megfelelő 3. Akár fordítva is megadhattam volna és a kis-nagy betű sem számít:

PS C:\> $b = [Bitjeim] "Kettő, egy"

PS C:\> $b

Egy, Kettő

Tömb formátumban is megadhatjuk az értéket:

PS C:\> $b = [Bitjeim] ("Négy", "Nyolc", "Egy")

PS C:\> [int]$b

13

Azt is lehet, hogy nem csak 1 bitet tartalmazó értékek szerepelnek a felsorolásban:

[Flags()] enum Bitjeim {

    Egy = 1

    Kettő = 2

    Három = 3

    Négy = 4

    Nyolc = 8

    Tizehat = 16

}

Itt a „Három” is szerepel az értékek között, így ez az értékadás erre fordul le:

PS C:\> $b = [Bitjeim] "Kettő, egy"

PS C:\> $b

Három

PS C:\> $b = [Bitjeim] "Kettő, egy, négy"

PS C:\> $b

Három, Négy

Az ilyen flag típusú felsorolások nagyon hasznosak lehetnek saját függvényeink paramétereinek megadásánál.



Word To HTML Converter