about_Classes_Inheritance

Krátký popis

Popisuje, jak můžete definovat třídy, které rozšiřují další typy.

Dlouhý popis

Třídy PowerShellu podporují dědičnost, která umožňuje definovat podřízenou třídu, která znovu používá (dědí), rozšiřuje nebo upravuje chování nadřazené třídy. Třída, jejíž členy jsou zděděné, se nazývá základní třída. Třída, která dědí členy základní třídy, se nazývá odvozená třída.

PowerShell podporuje pouze jednu dědičnost. Třída může dědit pouze z jedné třídy. Dědičnost je však tranzitivní, což umožňuje definovat hierarchii dědičnosti pro sadu typů. Jinými slovy, typ D může dědit z typu C, který dědí z typu B, který dědí ze základní třídy typu A. Vzhledem k tomu, že dědičnost je tranzitivní, jsou členové typu A k dispozici pro typ D.

Odvozené třídy nedědí všechny členy základní třídy. Následující členové nejsou zděděni:

  • Statické konstruktory, které inicializují statická data třídy.
  • Konstruktory instance, které voláte k vytvoření nové instance třídy. Každá třída musí definovat vlastní konstruktory.

Třídu můžete rozšířit vytvořením nové třídy, která je odvozena z existující třídy. Odvozená třída dědí vlastnosti a metody základní třídy. Podle potřeby můžete přidat nebo přepsat členy základní třídy.

Třídy mohou také dědit z rozhraní, která definují kontrakt. Třída, která dědí z rozhraní, musí implementovat tento kontrakt. Pokud ano, třída je použitelná jako jakákoli jiná třída implementovaná v daném rozhraní. Pokud třída dědí z rozhraní, ale neimplementuje rozhraní, PowerShell vyvolá chybu analýzy třídy.

Některé operátory PowerShellu závisí na třídě, která implementuje konkrétní rozhraní. Například operátor pouze kontroluje rovnost odkazů, -eq pokud třída implementuje System.IEquatable rozhraní. , -lt-gea -gt operátory -lepracují pouze na třídách, které implementují System.IComparable rozhraní.

Odvozená třída používá : syntaxi k rozšíření základní třídy nebo implementaci rozhraní. Odvozená třída by měla být vždy ponechána nejvíce v deklaraci třídy.

Tento příklad ukazuje základní syntaxi dědičnosti tříd PowerShellu.

Class Derived : Base {...}

Tento příklad ukazuje dědičnost s deklarací rozhraní přicházející po základní třídě.

Class Derived : Base, Interface {...}

Syntaxe

Dědičnost tříd používá následující syntaxe:

Syntaxe jednoho řádku

class <derived-class-name> : <base-class-or-interface-name>[, <interface-name>...] {
    <derived-class-body>
}

Příklad:

# Base class only
class Derived : Base {...}
# Interface only
class Derived : System.IComparable {...}
# Base class and interface
class Derived : Base, System.IComparable {...}

Víceřádkové syntaxe

class <derived-class-name> : <base-class-or-interface-name>[,
    <interface-name>...] {
    <derived-class-body>
}

Příklad:

class Derived : Base,
                System.IComparable,
                System.IFormattable,
                System.IConvertible {
    # Derived class definition
}

Příklady

Příklad 1 – Dědění a přepsání ze základní třídy

Následující příklad ukazuje chování zděděných vlastností s a bez přepsání. Po přečtení popisu spusťte bloky kódu v pořadí.

Definování základní třídy

První blok kódu definuje PublishedWork jako základní třídu. Má dvě statické vlastnosti: List a Artists. Dále definuje statickou RegisterWork() metodu, která přidá práci do statického seznamu vlastnost a umělci do vlastnosti Artists , napsání zprávy pro každou novou položku v seznamech.

Třída definuje tři vlastnosti instance, které popisují publikovanou práci. Nakonec definuje Register() metody a ToString() metody instance.

class PublishedWork {
    static [PublishedWork[]] $List    = @()
    static [string[]]        $Artists = @()

    static [void] RegisterWork([PublishedWork]$Work) {
        $wName   = $Work.Name
        $wArtist = $Work.Artist
        if ($Work -notin [PublishedWork]::List) {
            Write-Verbose "Adding work '$wName' to works list"
            [PublishedWork]::List += $Work
        } else {
            Write-Verbose "Work '$wName' already registered."
        }
        if ($wArtist -notin [PublishedWork]::Artists) {
            Write-Verbose "Adding artist '$wArtist' to artists list"
            [PublishedWork]::Artists += $wArtist
        } else {
            Write-Verbose "Artist '$wArtist' already registered."
        }
    }

    static [void] ClearRegistry() {
        Write-Verbose "Clearing PublishedWork registry"
        [PublishedWork]::List    = @()
        [PublishedWork]::Artists = @()
    }

    [string] $Name
    [string] $Artist
    [string] $Category

    [void] Init([string]$WorkType) {
        if ([string]::IsNullOrEmpty($this.Category)) {
            $this.Category = "${WorkType}s"
        }
    }

    PublishedWork() {
        $WorkType = $this.GetType().FullName
        $this.Init($WorkType)
        Write-Verbose "Defined a published work of type [$WorkType]"
    }

    PublishedWork([string]$Name, [string]$Artist) {
        $WorkType    = $this.GetType().FullName
        $this.Name   = $Name
        $this.Artist = $Artist
        $this.Init($WorkType)

        Write-Verbose "Defined '$Name' by $Artist as a published work of type [$WorkType]"
    }

    PublishedWork([string]$Name, [string]$Artist, [string]$Category) {
        $WorkType    = $this.GetType().FullName
        $this.Name   = $Name
        $this.Artist = $Artist
        $this.Init($WorkType)

        Write-Verbose "Defined '$Name' by $Artist ($Category) as a published work of type [$WorkType]"
    }

    [void]   Register() { [PublishedWork]::RegisterWork($this) }
    [string] ToString() { return "$($this.Name) by $($this.Artist)" }
}

Definování odvozené třídy bez přepsání

První odvozená třída je Album. Nepřepíše žádné vlastnosti ani metody. Přidá novou vlastnost instance, Žánry, které neexistují v základní třídě.

class Album : PublishedWork {
    [string[]] $Genres   = @()
}

Následující blok kódu ukazuje chování odvozené třídy Album . Nejprve nastaví $VerbosePreference tak, aby zprávy z metod třídy vysílaly do konzoly. Vytvoří tři instance třídy, zobrazí je v tabulce a pak je zaregistruje pomocí zděděné statické RegisterWork() metody. Potom volá stejnou statickou metodu přímo v základní třídě.

$VerbosePreference = 'Continue'
$Albums = @(
    [Album]@{
        Name   = 'The Dark Side of the Moon'
        Artist = 'Pink Floyd'
        Genres = 'Progressive rock', 'Psychedelic rock'
    }
    [Album]@{
        Name   = 'The Wall'
        Artist = 'Pink Floyd'
        Genres = 'Progressive rock', 'Art rock'
    }
    [Album]@{
        Name   = '36 Chambers'
        Artist = 'Wu-Tang Clan'
        Genres = 'Hip hop'
    }
)

$Albums | Format-Table
$Albums | ForEach-Object { [Album]::RegisterWork($_) }
$Albums | ForEach-Object { [PublishedWork]::RegisterWork($_) }
VERBOSE: Defined a published work of type [Album]
VERBOSE: Defined a published work of type [Album]
VERBOSE: Defined a published work of type [Album]

Genres                               Name                      Artist       Category
------                               ----                      ------       --------
{Progressive rock, Psychedelic rock} The Dark Side of the Moon Pink Floyd   Albums
{Progressive rock, Art rock}         The Wall                  Pink Floyd   Albums
{Hip hop}                            36 Chambers               Wu-Tang Clan Albums

VERBOSE: Adding work 'The Dark Side of the Moon' to works list
VERBOSE: Adding artist 'Pink Floyd' to artists list
VERBOSE: Adding work 'The Wall' to works list
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Adding work '36 Chambers' to works list
VERBOSE: Adding artist 'Wu-Tang Clan' to artists list

VERBOSE: Work 'The Dark Side of the Moon' already registered.
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Work 'The Wall' already registered.
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Work '36 Chambers' already registered.
VERBOSE: Artist 'Wu-Tang Clan' already registered.

Všimněte si, že i když třída Album nedefinovala hodnotu pro Category nebo žádné konstruktory, byla vlastnost definována výchozím konstruktorem základní třídy.

Ve podrobném zasílání zpráv druhé volání RegisterWork() metody hlásí, že díla a umělci jsou již zaregistrováni. I když první volání RegisterWork() bylo pro odvozenou třídu Album , použilo zděděnou statickou metodu ze základní PublishedWork třídy. Tato metoda aktualizovala statické vlastnosti List a Artist v základní třídě, kterou odvozená třída nepřepsala.

Další blok kódu vymaže registr a zavolá metodu Register() instance na objektech Album .

[PublishedWork]::ClearRegistry()
$Albums.Register()
VERBOSE: Clearing PublishedWork registry

VERBOSE: Adding work 'The Dark Side of the Moon' to works list
VERBOSE: Adding artist 'Pink Floyd' to artists list
VERBOSE: Adding work 'The Wall' to works list
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Adding work '36 Chambers' to works list
VERBOSE: Adding artist 'Wu-Tang Clan' to artists list

Metoda instance na objekty Album má stejný účinek jako volání statické metody na odvozené nebo základní třídy.

Následující blok kódu porovnává statické vlastnosti základní třídy a odvozené třídy, což ukazuje, že jsou stejné.

[pscustomobject]@{
    '[PublishedWork]::List'    = [PublishedWork]::List -join ",`n"
    '[Album]::List'            = [Album]::List -join ",`n"
    '[PublishedWork]::Artists' = [PublishedWork]::Artists -join ",`n"
    '[Album]::Artists'         = [Album]::Artists -join ",`n"
    'IsSame::List'             = (
        [PublishedWork]::List.Count -eq [Album]::List.Count -and
        [PublishedWork]::List.ToString() -eq [Album]::List.ToString()
    )
    'IsSame::Artists'          = (
        [PublishedWork]::Artists.Count -eq [Album]::Artists.Count -and
        [PublishedWork]::Artists.ToString() -eq [Album]::Artists.ToString()
    )
} | Format-List
[PublishedWork]::List    : The Dark Side of the Moon by Pink Floyd,
                           The Wall by Pink Floyd,
                           36 Chambers by Wu-Tang Clan
[Album]::List            : The Dark Side of the Moon by Pink Floyd,
                           The Wall by Pink Floyd,
                           36 Chambers by Wu-Tang Clan
[PublishedWork]::Artists : Pink Floyd,
                           Wu-Tang Clan
[Album]::Artists         : Pink Floyd,
                           Wu-Tang Clan
IsSame::List             : True
IsSame::Artists          : True

Definování odvozené třídy s přepsáními

Další blok kódu definuje třídu ilustrace dědící ze základní PublishedWork třídy. Nová třída rozšiřuje základní třídu definováním medium instance vlastnost s výchozí hodnotou Unknown.

Na rozdíl od odvozené třídy Album, Ilustrace přepíše následující vlastnosti a metody:

  • Přepíše statickou vlastnost Artists . Definice je stejná, ale třída ilustrace ji deklaruje přímo.
  • Přepíše vlastnost Instance kategorie a nastaví výchozí hodnotu na Illustrations.
  • Přepíše metodu ToString() instance tak, aby řetězcová reprezentace obrázku obsahovala médium, se kterým byla vytvořena.

Třída také definuje statickou RegisterIllustration() metodu pro první volání metody základní třídy RegisterWork() a pak přidá interpreta do přepsané artists static vlastnost na odvozené třídě.

Nakonec třída přepíše všechny tři konstruktory:

  1. Výchozí konstruktor je prázdný s výjimkou podrobné zprávy označující, že vytvořil obrázek.
  2. Další konstruktor přebírá dvě řetězcové hodnoty pro název a interpreta, který vytvořil ilustraci. Namísto implementace logiky pro nastavení vlastnosti Name a Artist konstruktor volá příslušný konstruktor ze základní třídy.
  3. Poslední konstruktor přebírá tři řetězcové hodnoty pro název, interpreta a médium obrázku. Oba konstruktory zapisují podrobnou zprávu označující, že vytvořily obrázek.
class Illustration : PublishedWork {
    static [string[]] $Artists = @()

    static [void] RegisterIllustration([Illustration]$Work) {
        $wArtist = $Work.Artist

        [PublishedWork]::RegisterWork($Work)

        if ($wArtist -notin [Illustration]::Artists) {
            Write-Verbose "Adding illustrator '$wArtist' to artists list"
            [Illustration]::Artists += $wArtist
        } else {
            Write-Verbose "Illustrator '$wArtist' already registered."
        }
    }

    [string] $Category = 'Illustrations'
    [string] $Medium   = 'Unknown'

    [string] ToString() {
        return "$($this.Name) by $($this.Artist) ($($this.Medium))"
    }

    Illustration() {
        Write-Verbose 'Defined an illustration'
    }

    Illustration([string]$Name, [string]$Artist) : base($Name, $Artist) {
        Write-Verbose "Defined '$Name' by $Artist ($($this.Medium)) as an illustration"
    }

    Illustration([string]$Name, [string]$Artist, [string]$Medium) {
        $this.Name = $Name
        $this.Artist = $Artist
        $this.Medium = $Medium

        Write-Verbose "Defined '$Name' by $Artist ($Medium) as an illustration"
    }
}

Následující blok kódu ukazuje chování odvozené třídy Ilustrace . Vytvoří tři instance třídy, zobrazí je v tabulce a pak je zaregistruje pomocí zděděné statické RegisterWork() metody. Potom volá stejnou statickou metodu přímo v základní třídě. Nakonec zapíše zprávy zobrazující seznam registrovaných umělců pro základní třídu a odvozenou třídu.

$Illustrations = @(
    [Illustration]@{
        Name   = 'The Funny Thing'
        Artist = 'Wanda Gág'
        Medium = 'Lithography'
    }
    [Illustration]::new('Millions of Cats', 'Wanda Gág')
    [Illustration]::new(
      'The Lion and the Mouse',
      'Jerry Pinkney',
      'Watercolor'
    )
)

$Illustrations | Format-Table
$Illustrations | ForEach-Object { [Illustration]::RegisterIllustration($_) }
$Illustrations | ForEach-Object { [PublishedWork]::RegisterWork($_) }
"Published work artists: $([PublishedWork]::Artists -join ', ')"
"Illustration artists: $([Illustration]::Artists -join ', ')"
VERBOSE: Defined a published work of type [Illustration]
VERBOSE: Defined an illustration
VERBOSE: Defined 'Millions of Cats' by Wanda Gág as a published work of type [Illustration]
VERBOSE: Defined 'Millions of Cats' by Wanda Gág (Unknown) as an illustration
VERBOSE: Defined a published work of type [Illustration]
VERBOSE: Defined 'The Lion and the Mouse' by Jerry Pinkney (Watercolor) as an illustration

Category      Medium      Name                   Artist
--------      ------      ----                   ------
Illustrations Lithography The Funny Thing        Wanda Gág
Illustrations Unknown     Millions of Cats       Wanda Gág
Illustrations Watercolor  The Lion and the Mouse Jerry Pinkney

VERBOSE: Adding work 'The Funny Thing' to works list
VERBOSE: Adding artist 'Wanda Gág' to artists list
VERBOSE: Adding illustrator 'Wanda Gág' to artists list
VERBOSE: Adding work 'Millions of Cats' to works list
VERBOSE: Artist 'Wanda Gág' already registered.
VERBOSE: Illustrator 'Wanda Gág' already registered.
VERBOSE: Adding work 'The Lion and the Mouse' to works list
VERBOSE: Adding artist 'Jerry Pinkney' to artists list
VERBOSE: Adding illustrator 'Jerry Pinkney' to artists list

VERBOSE: Work 'The Funny Thing' already registered.
VERBOSE: Artist 'Wanda Gág' already registered.
VERBOSE: Work 'Millions of Cats' already registered.
VERBOSE: Artist 'Wanda Gág' already registered.
VERBOSE: Work 'The Lion and the Mouse' already registered.
VERBOSE: Artist 'Jerry Pinkney' already registered.

Published work artists: Pink Floyd, Wu-Tang Clan, Wanda Gág, Jerry Pinkney

Illustration artists: Wanda Gág, Jerry Pinkney

Podrobné zasílání zpráv z vytváření instancí ukazuje, že:

  • Při vytváření první instance byl výchozí konstruktor základní třídy volána před výchozí konstruktor odvozené třídy.
  • Při vytváření druhé instance byl explicitně zděděný konstruktor volána pro základní třídu před konstruktor odvozené třídy.
  • Při vytváření třetí instance byl výchozí konstruktor základní třídy volána před konstruktor odvozené třídy.

Podrobné zprávy z RegisterWork() metody naznačují, že díla a umělci byli již zaregistrováni. Důvodem je to, RegisterIllustration() že metoda volala interně metodu RegisterWork() .

Při porovnávání hodnoty static Artist vlastnost pro základní i odvozenou třídu jsou však hodnoty odlišné. Vlastnost Artists pro odvozenou třídu zahrnuje pouze ilustrátory, nikoli umělce alba. Redefining Artist vlastnost v odvozené třídě zabraňuje třídy v vrácení statické vlastnosti základní třídy.

Konečný blok kódu volá metodu ToString() pro položky statické List vlastnost v základní třídě.

[PublishedWork]::List | ForEach-Object -Process { $_.ToString() }
The Dark Side of the Moon by Pink Floyd
The Wall by Pink Floyd
36 Chambers by Wu-Tang Clan
The Funny Thing by Wanda Gág (Lithography)
Millions of Cats by Wanda Gág (Unknown)
The Lion and the Mouse by Jerry Pinkney (Watercolor)

Instance alba vrátí pouze jméno a interpreta v řetězci. Instance ilustrace také zahrnovaly médium v závorkách, protože tato třída přerodil metodu ToString() .

Příklad 2 – Implementace rozhraní

Následující příklad ukazuje, jak může třída implementovat jedno nebo více rozhraní. Příklad rozšiřuje definici třídy Temperature , aby podporovala více operací a chování.

Definice počáteční třídy

Před implementací rozhraní je třída Temperature definována se dvěma vlastnostmi, stupněmi a měřítkem. Definuje konstruktory a tři metody instance pro vrácení instance ve stupních konkrétního škálování.

Třída definuje dostupná měřítka pomocí výčtu TemperatureScale .

class Temperature {
    [float]            $Degrees
    [TemperatureScale] $Scale

    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale   = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius    { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5/9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5/9 }
            Kelvin     { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius    { return $this.Degrees * 9/5 + 32 }
            Kelvin     { return $this.Degrees * 9/5 - 459.67 }
        }
        return $this.Degrees
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

V této základní implementaci však existuje několik omezení, jak je znázorněno v následujícím příkladu výstupu:

$Celsius    = [Temperature]::new()
$Fahrenheit = [Temperature]::new([TemperatureScale]::Fahrenheit)
$Kelvin     = [Temperature]::new(0, 'Kelvin')

$Celsius, $Fahrenheit, $Kelvin

"The temperatures are: $Celsius, $Fahrenheit, $Kelvin"

[Temperature]::new() -eq $Celsius

$Celsius -gt $Kelvin
Degrees      Scale
-------      -----
   0.00    Celsius
   0.00 Fahrenheit
   0.00     Kelvin

The temperatures are: Temperature, Temperature, Temperature

False

InvalidOperation:
Line |
  11 |  $Celsius -gt $Kelvin
     |  ~~~~~~~~~~~~~~~~~~~~
     | Cannot compare "Temperature" because it is not IComparable.

Výstup ukazuje, že instance Temperature:

  • Nezobrazujte se správně jako řetězce.
  • Nelze správně zkontrolovat ekvivalenci.
  • Nedá se porovnat.

Tyto tři problémy je možné vyřešit implementací rozhraní pro třídu.

Implementace IFormattable

Prvním rozhraním pro implementaci pro třídu Temperature je System.IFormattable. Toto rozhraní umožňuje formátování instance třídy jako různých řetězců. Aby bylo možné implementovat rozhraní, třída musí dědit z System.IFormattable a definovat metodu ToString() instance.

Metoda ToString() instance musí mít následující podpis:

[string] ToString(
    [string]$Format,
    [System.IFormatProvider]$FormatProvider
) {
    # Implementation
}

Podpis, který rozhraní vyžaduje, je uvedený v referenční dokumentaci.

Pro teplotu by třída měla podporovat tři formáty: C pro vrácení instance ve stupních Celsia, F vrácení v Fahrenheita a K vrácení v Kelvinu. Pro jakýkoli jiný formát by metoda měla vyvolat System.FormatException.

[string] ToString(
    [string]$Format,
    [System.IFormatProvider]$FormatProvider
) {
    # If format isn't specified, use the defined scale.
    if ([string]::IsNullOrEmpty($Format)) {
        $Format = switch ($this.Scale) {
            Celsius    { 'C' }
            Fahrenheit { 'F' }
            Kelvin     { 'K' }
        }
    }
    # If format provider isn't specified, use the current culture.
    if ($null -eq $FormatProvider) {
        $FormatProvider = [CultureInfo]::CurrentCulture
    }
    # Format the temperature.
    switch ($Format) {
        'C' {
            return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
        }
        'F' {
            return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
        }
        'K' {
            return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
        }
    }
    # If we get here, the format is invalid.
    throw [System.FormatException]::new(
        "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
    )
}

V této implementaci metoda ve výchozím nastavení škáluje instanci pro formát a aktuální jazykovou verzi při formátování samotné hodnoty číselného stupně. Pomocí To<Scale>() metod instance převede stupně, zformátuje je na dvě desetinná místa a připojí k řetězci odpovídající symbol stupně.

S implementovaným požadovaným podpisem může třída také definovat přetížení, aby bylo snazší vrátit formátovanou instanci.

[string] ToString([string]$Format) {
    return $this.ToString($Format, $null)
}

[string] ToString() {
    return $this.ToString($null, $null)
}

Následující kód ukazuje aktualizovanou definici teploty:

class Temperature : System.IFormattable {
    [float]            $Degrees
    [TemperatureScale] $Scale

    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5 / 9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5 / 9 }
            Kelvin { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees * 9 / 5 + 32 }
            Kelvin { return $this.Degrees * 9 / 5 - 459.67 }
        }
        return $this.Degrees
    }

    [string] ToString(
        [string]$Format,
        [System.IFormatProvider]$FormatProvider
    ) {
        # If format isn't specified, use the defined scale.
        if ([string]::IsNullOrEmpty($Format)) {
            $Format = switch ($this.Scale) {
                Celsius    { 'C' }
                Fahrenheit { 'F' }
                Kelvin     { 'K' }
            }
        }
        # If format provider isn't specified, use the current culture.
        if ($null -eq $FormatProvider) {
            $FormatProvider = [CultureInfo]::CurrentCulture
        }
        # Format the temperature.
        switch ($Format) {
            'C' {
                return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
            }
            'F' {
                return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
            }
            'K' {
                return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
            }
        }
        # If we get here, the format is invalid.
        throw [System.FormatException]::new(
            "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
        )
    }

    [string] ToString([string]$Format) {
        return $this.ToString($Format, $null)
    }

    [string] ToString() {
        return $this.ToString($null, $null)
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

Výstup přetížení metody je uveden v následujícím bloku.

$Temp = [Temperature]::new()
"The temperature is $Temp"
$Temp.ToString()
$Temp.ToString('K')
$Temp.ToString('F', $null)
The temperature is 0.00°C

0.00°C

273.15°K

32.00°F

Implementace IEquatable

Teď, když je možné naformátovat třídu Teploty pro čitelnost, musí být uživatelé schopni zkontrolovat, zda jsou dvě instance třídy stejné. Aby bylo možné tento test podporovat, třída musí implementovat rozhraní System.IEquatable .

Aby bylo možné implementovat rozhraní, třída musí dědit z System.IEquatable a definovat metodu Equals() instance. Metoda Equals() musí mít následující podpis:

[bool] Equals([object]$Other) {
    # Implementation
}

Podpis, který rozhraní vyžaduje, je uvedený v referenční dokumentaci.

Pro teplotu by třída měla podporovat pouze porovnání dvou instancí třídy. Pro jakoukoli jinou hodnotu nebo typ, včetně $null, by měl vrátit $false. Při porovnávání dvou teplot by metoda měla převést obě hodnoty na Kelvin, protože teploty mohou být ekvivalentní i s různými stupnici.

[bool] Equals([object]$Other) {
    # If the other object is null, we can't compare it.
    if ($null -eq $Other) {
        return $false
    }

    # If the other object isn't a temperature, we can't compare it.
    $OtherTemperature = $Other -as [Temperature]
    if ($null -eq $OtherTemperature) {
        return $false
    }

    # Compare the temperatures as Kelvin.
    return $this.ToKelvin() -eq $OtherTemperature.ToKelvin()
}

Při implementaci metody rozhraní je aktualizovaná definice pro Teplotu :

class Temperature : System.IFormattable, System.IEquatable[object] {
    [float]            $Degrees
    [TemperatureScale] $Scale

    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5 / 9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5 / 9 }
            Kelvin { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees * 9 / 5 + 32 }
            Kelvin { return $this.Degrees * 9 / 5 - 459.67 }
        }
        return $this.Degrees
    }

    [string] ToString(
        [string]$Format,
        [System.IFormatProvider]$FormatProvider
    ) {
        # If format isn't specified, use the defined scale.
        if ([string]::IsNullOrEmpty($Format)) {
            $Format = switch ($this.Scale) {
                Celsius    { 'C' }
                Fahrenheit { 'F' }
                Kelvin     { 'K' }
            }
        }
        # If format provider isn't specified, use the current culture.
        if ($null -eq $FormatProvider) {
            $FormatProvider = [CultureInfo]::CurrentCulture
        }
        # Format the temperature.
        switch ($Format) {
            'C' {
                return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
            }
            'F' {
                return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
            }
            'K' {
                return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
            }
        }
        # If we get here, the format is invalid.
        throw [System.FormatException]::new(
            "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
        )
    }

    [string] ToString([string]$Format) {
        return $this.ToString($Format, $null)
    }

    [string] ToString() {
        return $this.ToString($null, $null)
    }

    [bool] Equals([object]$Other) {
        # If the other object is null, we can't compare it.
        if ($null -eq $Other) {
            return $false
        }

        # If the other object isn't a temperature, we can't compare it.
        $OtherTemperature = $Other -as [Temperature]
        if ($null -eq $OtherTemperature) {
            return $false
        }

        # Compare the temperatures as Kelvin.
        return $this.ToKelvin() -eq $OtherTemperature.ToKelvin()
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

Následující blok ukazuje, jak se aktualizovaná třída chová:

$Celsius    = [Temperature]::new()
$Fahrenheit = [Temperature]::new(32, 'Fahrenheit')
$Kelvin     = [Temperature]::new([TemperatureScale]::Kelvin)

@"
Temperatures are: $Celsius, $Fahrenheit, $Kelvin
`$Celsius.Equals(`$Fahrenheit) = $($Celsius.Equals($Fahrenheit))
`$Celsius -eq `$Fahrenheit     = $($Celsius -eq $Fahrenheit)
`$Celsius -ne `$Kelvin         = $($Celsius -ne $Kelvin)
"@
Temperatures are: 0.00°C, 32.00°F, 0.00°K

$Celsius.Equals($Fahrenheit) = True
$Celsius -eq $Fahrenheit     = True
$Celsius -ne $Kelvin         = True

Implementace IComparable

Posledním rozhraním pro implementaci pro třídu Temperature je System.IComparable. Když třída implementuje toto rozhraní, mohou uživatelé použít -lt, -le, -gta -ge operátory porovnat instance třídy.

K implementaci rozhraní musí třída dědit z System.IComparable a definovat Equals() instanci metody. Metoda Equals() musí mít následující podpis:

[int] CompareTo([Object]$Other) {
    # Implementation
}

Podpis, který rozhraní vyžaduje, je uvedený v referenční dokumentaci.

Pro teplotu by třída měla podporovat pouze porovnání dvou instancí třídy. Vzhledem k tomu, že základní typ pro vlastnost Degrees , i když je převeden na jiné měřítko, je číslo s plovoucí desetinou čárkou, metoda může spoléhat na základní typ pro skutečné porovnání.

[int] CompareTo([object]$Other) {
    # If the other object's null, consider this instance "greater than" it
    if ($null -eq $Other) {
        return 1
    }
    # If the other object isn't a temperature, we can't compare it.
    $OtherTemperature = $Other -as [Temperature]
    if ($null -eq $OtherTemperature) {
        throw [System.ArgumentException]::new(
            "Object must be of type 'Temperature'."
        )
    }
    # Compare the temperatures as Kelvin.
    return $this.ToKelvin().CompareTo($OtherTemperature.ToKelvin())
}

Konečná definice pro třídu Temperature je:

class Temperature : System.IFormattable,
                    System.IComparable,
                    System.IEquatable[object] {
    # Instance properties
    [float]            $Degrees
    [TemperatureScale] $Scale

    # Constructors
    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5 / 9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5 / 9 }
            Kelvin { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees * 9 / 5 + 32 }
            Kelvin { return $this.Degrees * 9 / 5 - 459.67 }
        }
        return $this.Degrees
    }

    [string] ToString(
        [string]$Format,
        [System.IFormatProvider]$FormatProvider
    ) {
        # If format isn't specified, use the defined scale.
        if ([string]::IsNullOrEmpty($Format)) {
            $Format = switch ($this.Scale) {
                Celsius    { 'C' }
                Fahrenheit { 'F' }
                Kelvin     { 'K' }
            }
        }
        # If format provider isn't specified, use the current culture.
        if ($null -eq $FormatProvider) {
            $FormatProvider = [CultureInfo]::CurrentCulture
        }
        # Format the temperature.
        switch ($Format) {
            'C' {
                return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
            }
            'F' {
                return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
            }
            'K' {
                return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
            }
        }
        # If we get here, the format is invalid.
        throw [System.FormatException]::new(
            "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
        )
    }

    [string] ToString([string]$Format) {
        return $this.ToString($Format, $null)
    }

    [string] ToString() {
        return $this.ToString($null, $null)
    }

    [bool] Equals([object]$Other) {
        # If the other object is null, we can't compare it.
        if ($null -eq $Other) {
            return $false
        }
        # If the other object isn't a temperature, we can't compare it.
        $OtherTemperature = $Other -as [Temperature]
        if ($null -eq $OtherTemperature) {
            return $false
        }
        # Compare the temperatures as Kelvin.
        return $this.ToKelvin() -eq $OtherTemperature.ToKelvin()
    }
    [int] CompareTo([object]$Other) {
        # If the other object's null, consider this instance "greater than" it
        if ($null -eq $Other) {
            return 1
        }
        # If the other object isn't a temperature, we can't compare it.
        $OtherTemperature = $Other -as [Temperature]
        if ($null -eq $OtherTemperature) {
            throw [System.ArgumentException]::new(
                "Object must be of type 'Temperature'."
            )
        }
        # Compare the temperatures as Kelvin.
        return $this.ToKelvin().CompareTo($OtherTemperature.ToKelvin())
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

S úplnou definicí můžou uživatelé formátovat a porovnávat instance třídy v PowerShellu jako jakýkoli integrovaný typ.

$Celsius    = [Temperature]::new()
$Fahrenheit = [Temperature]::new(32, 'Fahrenheit')
$Kelvin     = [Temperature]::new([TemperatureScale]::Kelvin)

@"
Temperatures are: $Celsius, $Fahrenheit, $Kelvin
`$Celsius.Equals(`$Fahrenheit)    = $($Celsius.Equals($Fahrenheit))
`$Celsius.Equals(`$Kelvin)        = $($Celsius.Equals($Kelvin))
`$Celsius.CompareTo(`$Fahrenheit) = $($Celsius.CompareTo($Fahrenheit))
`$Celsius.CompareTo(`$Kelvin)     = $($Celsius.CompareTo($Kelvin))
`$Celsius -lt `$Fahrenheit        = $($Celsius -lt $Fahrenheit)
`$Celsius -le `$Fahrenheit        = $($Celsius -le $Fahrenheit)
`$Celsius -eq `$Fahrenheit        = $($Celsius -eq $Fahrenheit)
`$Celsius -gt `$Kelvin            = $($Celsius -gt $Kelvin)
"@
Temperatures are: 0.00°C, 32.00°F, 0.00°K
$Celsius.Equals($Fahrenheit)    = True
$Celsius.Equals($Kelvin)        = False
$Celsius.CompareTo($Fahrenheit) = 0
$Celsius.CompareTo($Kelvin)     = 1
$Celsius -lt $Fahrenheit        = False
$Celsius -le $Fahrenheit        = True
$Celsius -eq $Fahrenheit        = True
$Celsius -gt $Kelvin            = True

Příklad 3 – Dědění z obecné základní třídy

Tento příklad ukazuje, jak lze odvodit z obecné třídy, jako je System.Collections.Generic.List.

Použití předdefinované třídy jako parametru typu

Spusťte následující blok kódu. Ukazuje, jak může nová třída dědit z obecného typu, pokud je parametr typu již definován v době analýzy.

class ExampleStringList : System.Collections.Generic.List[string] {}

$List = [ExampleStringList]::New()
$List.AddRange([string[]]@('a','b','c'))
$List.GetType() | Format-List -Property Name, BaseType
$List
Name     : ExampleStringList
BaseType : System.Collections.Generic.List`1[System.String]

a
b
c

Použití vlastní třídy jako parametru typu

Další blok kódu nejprve definuje novou třídu ExampleItem s jednou instancí vlastnost a metodu ToString() . Pak definuje ExampleItemList třídy dědění z System.Collections.Generic.List základní třídy s ExampleItem jako parametr typu.

Zkopírujte celý blok kódu a spusťte ho jako jeden příkaz.

class ExampleItem {
    [string] $Name
    [string] ToString() { return $this.Name }
}
class ExampleItemList : System.Collections.Generic.List[ExampleItem] {}
ParentContainsErrorRecordException: An error occurred while creating the pipeline.

Spuštění celého bloku kódu vyvolá chybu, protože PowerShell ještě nenačetl třídu ExampleItem do modulu runtime. Název třídy nelze použít jako parametr typu pro základní třídu System.Collections.Generic.List .

Spusťte následující bloky kódu v pořadí, v jakém jsou definované.

class ExampleItem {
    [string] $Name
    [string] ToString() { return $this.Name }
}
class ExampleItemList : System.Collections.Generic.List[ExampleItem] {}

Tentokrát PowerShell nevyvolá žádné chyby. Obě třídy jsou nyní definovány. Spuštěním následujícího bloku kódu zobrazte chování nové třídy.

$List = [ExampleItemList]::New()
$List.AddRange([ExampleItem[]]@(
    [ExampleItem]@{ Name = 'Foo' }
    [ExampleItem]@{ Name = 'Bar' }
    [ExampleItem]@{ Name = 'Baz' }
))
$List.GetType() | Format-List -Property Name, BaseType
$List
Name     : ExampleItemList
BaseType : System.Collections.Generic.List`1[ExampleItem]

Name
----
Foo
Bar
Baz

Odvození obecného s parametrem vlastního typu v modulu

Následující bloky kódu ukazují, jak můžete definovat třídu, která dědí z obecné základní třídy, která používá vlastní typ pro parametr typu.

Uložte následující blok kódu jako GenericExample.psd1.

@{
    RootModule        = 'GenericExample.psm1'
    ModuleVersion     = '0.1.0'
    GUID              = '2779fa60-0b3b-4236-b592-9060c0661ac2'
}

Uložte následující blok kódu jako GenericExample.InventoryItem.psm1.

class InventoryItem {
    [string] $Name
    [int]    $Count

    InventoryItem() {}
    InventoryItem([string]$Name) {
        $this.Name = $Name
    }
    InventoryItem([string]$Name, [int]$Count) {
        $this.Name  = $Name
        $this.Count = $Count
    }

    [string] ToString() {
        return "$($this.Name) ($($this.Count))"
    }
}

Uložte následující blok kódu jako GenericExample.psm1.

using namespace System.Collections.Generic
using module ./GenericExample.InventoryItem.psm1

class Inventory : List[InventoryItem] {}

# Define the types to export with type accelerators.
$ExportableTypes =@(
    [InventoryItem]
    [Inventory]
)
# Get the internal TypeAccelerators class to use its static methods.
$TypeAcceleratorsClass = [psobject].Assembly.GetType(
    'System.Management.Automation.TypeAccelerators'
)
# Ensure none of the types would clobber an existing type accelerator.
# If a type accelerator with the same name exists, throw an exception.
$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get
foreach ($Type in $ExportableTypes) {
    if ($Type.FullName -in $ExistingTypeAccelerators.Keys) {
        $Message = @(
            "Unable to register type accelerator '$($Type.FullName)'"
            'Accelerator already exists.'
        ) -join ' - '

        throw [System.Management.Automation.ErrorRecord]::new(
            [System.InvalidOperationException]::new($Message),
            'TypeAcceleratorAlreadyExists',
            [System.Management.Automation.ErrorCategory]::InvalidOperation,
            $Type.FullName
        )
    }
}
# Add type accelerators for every exportable type.
foreach ($Type in $ExportableTypes) {
    $TypeAcceleratorsClass::Add($Type.FullName, $Type)
}
# Remove type accelerators when the module is removed.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    foreach($Type in $ExportableTypes) {
        $TypeAcceleratorsClass::Remove($Type.FullName)
    }
}.GetNewClosure()

Tip

Kořenový modul přidá vlastní typy do akcelerátorů typů PowerShellu. Tento model umožňuje uživatelům modulů okamžitě přistupovat k IntelliSense a automatickému dokončování pro vlastní typy, aniž by museli nejprve použít using module příkaz.

Další informace o tomto vzoru najdete v části Export s akcelerátory typů about_Classes.

Importujte modul a ověřte výstup.

Import-Module ./GenericExample.psd1

$Inventory = [Inventory]::new()
$Inventory.GetType() | Format-List -Property Name, BaseType

$Inventory.Add([InventoryItem]::new('Bucket', 2))
$Inventory.Add([InventoryItem]::new('Mop'))
$Inventory.Add([InventoryItem]@{ Name = 'Broom' ; Count = 4 })
$Inventory
Name     : Inventory
BaseType : System.Collections.Generic.List`1[InventoryItem]

Name   Count
----   -----
Bucket     2
Mop        0
Broom      4

Modul se načte bez chyb, protože třída InventoryItem je definována v jiném souboru modulu, než je třída Inventory . Obě třídy jsou k dispozici pro uživatele modulů.

Dědění základní třídy

Když třída dědí ze základní třídy, dědí vlastnosti a metody základní třídy. Nedědí konstruktory základní třídy přímo, ale může je volat.

Pokud je základní třída definována v .NET místo PowerShellu, mějte na paměti, že:

  • Třídy PowerShellu nemůžou dědit z zapečetěných tříd.
  • Při dědění z obecné základní třídy nemůže být parametr typu pro obecnou třídu odvozenou třídou. Použití odvozené třídy jako parametru typu vyvolá chybu analýzy.

Pokud chcete zjistit, jak dědičnost a přepsání funguje pro odvozené třídy, podívejte se na příklad 1.

Odvozené konstruktory tříd

Odvozené třídy nedědí přímo konstruktory základní třídy. Pokud základní třída definuje výchozí konstruktor a odvozená třída nedefinuje žádné konstruktory, nové instance odvozené třídy používají výchozí konstruktor základní třídy. Pokud základní třída nedefinuje výchozí konstruktor, odvozená třída musí explicitně definovat alespoň jeden konstruktor.

Konstruktory odvozené třídy mohou vyvolat konstruktor ze základní třídy s klíčovým slovem base . Pokud odvozená třída explicitně nevyvolá konstruktor ze základní třídy, vyvolá místo toho výchozí konstruktor základní třídy.

Chcete-li vyvolat nedefault základní konstruktor, přidejte : base(<parameters>) za parametry konstruktoru a před blok těla.

class <derived-class> : <base-class> {
    <derived-class>(<derived-parameters>) : <base-class>(<base-parameters>) {
        # initialization code
    }
}

Při definování konstruktoru, který volá konstruktor základní třídy, mohou být parametry některé z následujících položek:

  • Proměnná libovolného parametru v konstruktoru odvozené třídy.
  • Libovolná statická hodnota.
  • Libovolný výraz, který se vyhodnotí jako hodnota typu parametru.

Třída Ilustrace v příkladu 1 ukazuje, jak odvozená třída může používat konstruktory základní třídy.

Metody odvozené třídy

Když třída je odvozena ze základní třídy, dědí metody základní třídy a jejich přetížení. Všechny přetížení metody definované na základní třídě, včetně skrytých metod, jsou k dispozici v odvozené třídě.

Odvozená třída může přepsat přetížení zděděné metody opětovným definováním v definici třídy. Chcete-li přepsat přetížení, musí být typy parametrů stejné jako pro základní třídu. Typ výstupu přetížení se může lišit.

Na rozdíl od konstruktorů metody nemůžou : base(<parameters>) syntaxi použít k vyvolání přetížení základní třídy pro metodu. Redefined přetížení odvozené třídy zcela nahrazuje přetížení definované základní třídou. Chcete-li volat metodu základní třídy pro instanci, přetypujte proměnnou instance ($this) na základní třídu před voláním metody.

Následující fragment kódu ukazuje, jak odvozená třída může volat metodu základní třídy.

class BaseClass {
    [bool] IsTrue() { return $true }
}
class DerivedClass : BaseClass {
    [bool] IsTrue()     { return $false }
    [bool] BaseIsTrue() { return ([BaseClass]$this).IsTrue() }
}

@"
[BaseClass]::new().IsTrue()        = $([BaseClass]::new().IsTrue())
[DerivedClass]::new().IsTrue()     = $([DerivedClass]::new().IsTrue())
[DerivedClass]::new().BaseIsTrue() = $([DerivedClass]::new().BaseIsTrue())
"@
[BaseClass]::new().IsTrue()        = True
[DerivedClass]::new().IsTrue()     = False
[DerivedClass]::new().BaseIsTrue() = True

Rozšířená ukázka znázorňující, jak odvozená třída může přepsat zděděné metody, naleznete v ilustraci třídy v příkladu 1.

Odvozené vlastnosti třídy

Když třída je odvozena od základní třídy, dědí vlastnosti základní třídy. Všechny vlastnosti definované v základní třídě, včetně skrytých vlastností, jsou k dispozici v odvozené třídě.

Odvozená třída může přepsat zděděnou vlastnost tím, že ji předefinuje v definici třídy. Vlastnost odvozené třídy používá redefinovaný typ a výchozí hodnotu, pokud existuje. Pokud zděděná vlastnost definovala výchozí hodnotu a předdefinovaná vlastnost ne, zděděná vlastnost nemá žádnou výchozí hodnotu.

Pokud odvozená třída nepřepíše statickou vlastnost, přístup ke statické vlastnosti prostřednictvím odvozené třídy přistupuje ke statické vlastnosti základní třídy. Úprava hodnoty vlastnosti prostřednictvím odvozené třídy upraví hodnotu základní třídy. Všechny ostatní odvozené třídy, které nepřepíší statickou vlastnost, také používá hodnotu vlastnosti základní třídy. Aktualizace hodnoty zděděné statické vlastnosti ve třídě, která nepřepíše vlastnost, může mít nezamýšlené účinky pro třídy odvozené ze stejné základní třídy.

Příklad 1 ukazuje, jak odvozené třídy, které dědí, rozšiřují a přepisují vlastnosti základní třídy.

Odvození z obecných typů

Pokud třída je odvozena od obecného, musí být parametr typu již definován před tím, než PowerShell parsuje odvozenou třídu. Pokud je parametr typu pro obecný třída PowerShellu nebo výčet definovaný ve stejném souboru nebo bloku kódu, PowerShell vyvolá chybu.

Chcete-li odvodit třídu z obecné základní třídy s vlastním typem jako parametr typu, definujte třídu nebo výčet parametru typu v jiném souboru nebo modulu a pomocí using module příkazu načtěte definici typu.

Příklad znázorňující, jak dědit z obecné základní třídy, naleznete v příkladu 3.

Užitečné třídy pro dědění

Existuje několik tříd, které mohou být užitečné dědit při vytváření modulů PowerShellu. Tato část uvádí několik základních tříd a třídy odvozené z nich lze použít.

  • System.Attribute – Odvození tříd definující atributy, které lze použít pro proměnné, parametry, třídy a definice výčtu a další.
  • System.Management.Automation.ArgumentTransformationAttribute – Odvození tříd pro zpracování převodu vstupu proměnné nebo parametru na konkrétní datový typ.
  • System.Management.Automation.ValidateArgumentsAttribute – Odvození tříd pro použití vlastního ověřování na proměnné, parametry a vlastnosti třídy.
  • System.Collections.Generic.List – Odvození tříd, které usnadňují vytváření a správu seznamů určitého datového typu.
  • System.Exception – Odvození tříd pro definování vlastních chyb

Implementace rozhraní

Třída PowerShellu, která implementuje rozhraní, musí implementovat všechny členy tohoto rozhraní. Vynechání členů rozhraní implementace způsobí chybu parsování času ve skriptu.

Poznámka:

PowerShell nepodporuje deklarování nových rozhraní ve skriptu PowerShellu. Místo toho musí být rozhraní deklarována v kódu .NET a přidána do relace pomocí Add-Type rutiny using assembly nebo příkazu.

Když třída implementuje rozhraní, lze ji použít jako jakoukoli jinou třídu, která implementuje toto rozhraní. Některé příkazy a operace omezují jejich podporované typy na třídy, které implementují konkrétní rozhraní.

Pokud chcete zkontrolovat ukázkovou implementaci rozhraní, podívejte se na příklad 2.

Užitečná rozhraní pro implementaci

Existuje několik tříd rozhraní, které mohou být užitečné dědit při vytváření modulů PowerShellu. Tato část uvádí několik základních tříd a třídy odvozené z nich lze použít.

  • System.IEquatable – toto rozhraní umožňuje uživatelům porovnat dvě instance třídy. Pokud třída toto rozhraní neimplementuje, PowerShell kontroluje ekvivalenci mezi dvěma instancemi pomocí rovnosti odkazů. Jinými slovy, instance třídy se rovná pouze sobě, i když jsou hodnoty vlastností ve dvou instancích stejné.
  • System.IComparable - Toto rozhraní umožňuje uživatelům porovnávat instance třídy s -leoperátory , -lt, -gea -gt porovnání. Pokud třída toto rozhraní neimplementuje, tyto operátory vyvolá chybu.
  • System.IFormattable – Toto rozhraní umožňuje uživatelům formátovat instance třídy do různých řetězců. To je užitečné pro třídy, které mají více než jednu standardní řetězcovou reprezentaci, jako jsou rozpočtové položky, bibliografie a teploty.
  • System.IConvertible – Toto rozhraní umožňuje uživatelům převádět instance třídy na jiné typy modulu runtime. To je užitečné pro třídy, které mají základní číselnou hodnotu nebo lze převést na jednu.

Omezení

  • PowerShell nepodporuje definování rozhraní v kódu skriptu.

    Alternativní řešení: Definujte rozhraní v jazyce C# a odkazujte na sestavení, které definuje rozhraní.

  • Třídy PowerShellu mohou dědit pouze z jedné základní třídy.

    Alternativní řešení: Dědičnost tříd je tranzitivní. Odvozená třída může dědit z jiné odvozené třídy získat vlastnosti a metody základní třídy.

  • Při dědění z obecné třídy nebo rozhraní musí být parametr typu pro obecný již definován. Třída nemůže definovat sama sebe jako parametr typu pro třídu nebo rozhraní.

    Alternativní řešení: Chcete-li odvodit z obecné základní třídy nebo rozhraní, definujte vlastní typ v jiném .psm1 souboru a použijte příkaz using module k načtení typu. Neexistuje žádné alternativní řešení pro použití vlastního typu jako parametru typu při dědění z obecného typu.

Viz také