about_Classes_Constructors

Krátký popis

Popisuje, jak definovat konstruktory pro třídy PowerShellu.

Dlouhý popis

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 mohou mít parametry pro inicializaci datových členů nového objektu.

Konstruktory třídy PowerShellu jsou definovány jako speciální metody třídy. Chovají se stejně jako metody třídy PowerShellu s následujícími výjimkami:

  • Konstruktory nemají výstupní typ. Klíčové slovo nemůžou return použít.
  • Konstruktory mají vždy stejný název jako třída.
  • Konstruktory nelze volat přímo. Spustí se pouze při vytvoření instance.
  • Konstruktory se ve výstupu rutiny Get-Member nikdy nezobrazí.

Další informace o metodách třídy PowerShellu najdete v tématu about_Classes_Methods.

Třída může mít definované nula 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 jejich 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ů.

Můžete také definovat statický konstruktor bez parametrů.

Syntaxe

Konstruktory tříd používají následující syntaxe:

Výchozí syntaxe konstruktoru

<class-name> () [: base([<params>])] {
    <body>
}

Syntaxe statického konstruktoru

static <class-name> () [: base([<params>])] {
    <body>
}

Syntaxe parametrizovaného konstruktoru (jeden řádek)

<class-name> ([[<parameter-type>]$<parameter-name>[, [<parameter-type>]$<parameter-name>...]]) [: base([<params>])] {
    <body>
}

Syntaxe parametrizovaného konstruktoru (víceřádkové)

<class-name> (
    [<parameter-type>]$<parameter-name>[,
    [<parameter-type>]$<parameter-name>...]
) [: base([<params>])] {
    <body>
}

Příklady

Příklad 1 – Definování třídy s výchozím konstruktorem

Třída ExampleBook1 nedefinuje konstruktor. Místo toho používá automatický výchozí konstruktor.

class ExampleBook1 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn
}

[ExampleBook1]::new()
Name Author Pages PublishedOn
---- ------ ----- -----------
                0 1/1/0001 12:00:00 AM

Poznámka:

Výchozí hodnota vlastností Name a Author je $null , protože jsou zadány jako řetězce, což je typ odkazu. Ostatní vlastnosti mají výchozí hodnotu pro jejich definovaný typ, protože se jedná o vlastnosti typu hodnoty. Další informace o výchozích hodnotách vlastností najdete v tématu Výchozí hodnoty vlastností v about_Classes_Properties.

Příklad 2 – Přepsání výchozího konstruktoru

ExampleBook2 explicitně definuje výchozí konstruktor a nastaví hodnoty PublishedOn na aktuální datum a Pages na 1.

class ExampleBook2 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn

    ExampleBook2() {
        $this.PublishedOn = (Get-Date).Date
        $this.Pages       = 1
    }
}

[ExampleBook2]::new()
Name Author Pages PublishedOn
---- ------ ----- -----------
                1 11/1/2023 12:00:00 AM

Příklad 3 – Definování přetížení konstruktoru

Třída ExampleBook3 definuje tři přetížení konstruktoru, což uživatelům umožňuje vytvořit instanci třídy z hashtable, předáním každé hodnoty vlastnosti a předáním názvu knihy a autora. Třída nedefinuje výchozí konstruktor.

class ExampleBook3 {
    [string]   $Name
    [string]   $Author
    [int]      $Pages
    [datetime] $PublishedOn

    ExampleBook3([hashtable]$Info) {
        switch ($Info.Keys) {
            'Name'        { $this.Name        = $Info.Name }
            'Author'      { $this.Author      = $Info.Author }
            'Pages'       { $this.Pages       = $Info.Pages }
            'PublishedOn' { $this.PublishedOn = $Info.PublishedOn }
        }
    }

    ExampleBook3(
        [string]   $Name,
        [string]   $Author,
        [int]      $Pages,
        [datetime] $PublishedOn
    ) {
        $this.Name        = $Name
        $this.Author      = $Author
        $this.Pages       = $Pages
        $this.PublishedOn = $PublishedOn
    }

    ExampleBook3([string]$Name, [string]$Author) {
        $this.Name   = $Name
        $this.Author = $Author
    }
}

[ExampleBook3]::new(@{
    Name        = 'The Hobbit'
    Author      = 'J.R.R. Tolkien'
    Pages       = 310
    PublishedOn = '1937-09-21'
})
[ExampleBook3]::new('The Hobbit', 'J.R.R. Tolkien', 310, '1937-09-21')
[ExampleBook3]::new('The Hobbit', 'J.R.R. Tolkien')
[ExampleBook3]::new()
Name       Author         Pages PublishedOn
----       ------         ----- -----------
The Hobbit J.R.R. Tolkien   310 9/21/1937 12:00:00 AM
The Hobbit J.R.R. Tolkien   310 9/21/1937 12:00:00 AM
The Hobbit J.R.R. Tolkien     0 1/1/0001 12:00:00 AM

MethodException:
Line |
  42 |  [ExampleBook3]::new()
     |  ~~~~~~~~~~~~~~~~~~~~~
     | Cannot find an overload for "new" and the argument count: "0".

Volání výchozího konstruktoru vrátí výjimku metody. Automatický výchozí konstruktor je definován pouze pro třídu, pokud třída nedefinuje žádné konstruktory. Protože ExampleBook3 definuje více přetížení, výchozí konstruktor není automaticky přidán do třídy.

Příklad 4 – řetězení konstruktorů se sdílenou metodou

Tento příklad ukazuje, jak můžete pro konstruktory psát opakovaně použitelný sdílený kód. Třídy PowerShellu nemůžou používat řetězení konstruktorů, takže tato ukázková třída místo toho definuje metodu Init() . Metoda má několik přetížení. Přetížení s menším počtem parametrů volají explicitnější přetížení s výchozími hodnotami pro nespecifikované parametry.

class ExampleBook4 {
    [string]   $Name
    [string]   $Author
    [datetime] $PublishedOn
    [int]      $Pages

    ExampleBook4() {
        $this.Init()
    }
    ExampleBook4([string]$Name) {
        $this.Init($Name)
    }
    ExampleBook4([string]$Name, [string]$Author) {
        $this.Init($Name, $Author)
    }
    ExampleBook4([string]$Name, [string]$Author, [datetime]$PublishedOn) {
        $this.Init($Name, $Author, $PublishedOn)
    }
    ExampleBook4(
      [string]$Name,
      [string]$Author,
      [datetime]$PublishedOn,
      [int]$Pages
    ) {
        $this.Init($Name, $Author, $PublishedOn, $Pages)
    }

    hidden Init() {
        $this.Init('Unknown')
    }
    hidden Init([string]$Name) {
        $this.Init($Name, 'Unknown')
    }
    hidden Init([string]$Name, [string]$Author) {
        $this.Init($Name, $Author, (Get-Date).Date)
    }
    hidden Init([string]$Name, [string]$Author, [datetime]$PublishedOn) {
        $this.Init($Name, $Author, $PublishedOn, 1)
    }
    hidden Init(
        [string]$Name,
        [string]$Author,
        [datetime]$PublishedOn,
        [int]$Pages
      ) {
        $this.Name        = $Name
        $this.Author      = $Author
        $this.PublishedOn = $PublishedOn
        $this.Pages       = $Pages
    }
}

[ExampleBook4]::new()
[ExampleBook4]::new('The Hobbit')
[ExampleBook4]::new('The Hobbit', 'J.R.R. Tolkien')
[ExampleBook4]::new('The Hobbit', 'J.R.R. Tolkien', (Get-Date '1937-9-21'))
[ExampleBook4]::new(
    'The Hobbit',
    'J.R.R. Tolkien',
    (Get-Date '1937-9-21'),
    310
)
Name       Author         PublishedOn           Pages
----       ------         -----------           -----
Unknown    Unknown        11/1/2023 12:00:00 AM     1
The Hobbit Unknown        11/1/2023 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 11/1/2023 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 9/21/1937 12:00:00 AM     1
The Hobbit J.R.R. Tolkien 9/21/1937 12:00:00 AM   310

Příklad 5 – konstruktory odvozené třídy

Následující příklady používají třídy, které definují statické, výchozí a parametrizované konstruktory pro základní třídu a odvozenou třídu, která dědí ze základní třídy.

class BaseExample {
    static [void] DefaultMessage([type]$Type) {
        Write-Verbose "[$($Type.Name)] default constructor"
    }

    static [void] StaticMessage([type]$Type) {
        Write-Verbose "[$($Type.Name)] static constructor"
    }

    static [void] ParamMessage([type]$Type, [object]$Value) {
        Write-Verbose "[$($Type.Name)] param constructor ($Value)"
    }

    static BaseExample() { [BaseExample]::StaticMessage([BaseExample])  }
    BaseExample()        { [BaseExample]::DefaultMessage([BaseExample]) }
    BaseExample($Value)  { [BaseExample]::ParamMessage([BaseExample], $Value) }
}

class DerivedExample : BaseExample {
    static DerivedExample() { [BaseExample]::StaticMessage([DerivedExample])  }
           DerivedExample() { [BaseExample]::DefaultMessage([DerivedExample]) }

    DerivedExample([int]$Number) : base($Number) {
        [BaseExample]::ParamMessage([DerivedExample], $Number)
    }
    DerivedExample([string]$String) {
        [BaseExample]::ParamMessage([DerivedExample], $String)
    }
}

Následující blok ukazuje podrobné zasílání zpráv pro volání konstruktorů základní třídy. Zpráva statického konstruktoru se vygeneruje pouze při prvním vytvoření instance třídy.

PS> $VerbosePreference = 'Continue'
PS> $b = [BaseExample]::new()

VERBOSE: [BaseExample] static constructor
VERBOSE: [BaseExample] default constructor

PS> $b = [BaseExample]::new()

VERBOSE: [BaseExample] default constructor

PS> $b = [BaseExample]::new(1)

VERBOSE: [BaseExample] param constructor (1)

Další blok ukazuje podrobné zasílání zpráv pro volání konstruktorů odvozené třídy v nové relaci. Při prvním zavolání konstruktoru odvozené třídy se volají statické konstruktory základní třídy a odvozené třídy. Tyto konstruktory se v relaci znovu nevolají. Konstruktory základní třídy vždy běží před konstruktory pro odvozenou třídu.

PS> $VerbosePreference = 'Continue'
PS> $c = [DerivedExample]::new()

VERBOSE: [BaseExample] static constructor
VERBOSE: [DerivedExample] static constructor
VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] default constructor

PS> $c = [DerivedExample]::new()

VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] default constructor

PS> $c = [DerivedExample]::new(1)

VERBOSE: [BaseExample] param constructor (1)
VERBOSE: [DerivedExample] param constructor (1)

PS> $c = [DerivedExample]::new('foo')

VERBOSE: [BaseExample] default constructor
VERBOSE: [DerivedExample] param constructor (foo)

Řazení spuštění konstruktoru

Při vytvoření instance třídy se spustí kód jednoho nebo více konstruktorů.

U tříd, které nedědí z jiné třídy, je řazení následující:

  1. Statický konstruktor pro třídu.
  2. Příslušné přetížení konstruktoru pro třídu.

Pro odvozené třídy, které dědí z jiné třídy, řazení je:

  1. Statický konstruktor základní třídy.
  2. Statický konstruktor pro odvozenou třídu.
  3. Pokud konstruktor odvozené třídy explicitně volá přetížení základního konstruktoru, spustí tento konstruktor pro základní třídu. Pokud nevolá explicitně základní konstruktor, spustí výchozí konstruktor základní třídy.
  4. Příslušné přetížení konstruktoru pro odvozenou třídu.

Ve všech případech se statické konstruktory spouští pouze jednou v relaci.

Příklad chování a řazení konstruktoru naleznete v příkladu 5.

Skryté konstruktory

Konstruktory třídy můžete skrýt deklarováním pomocí klíčového hidden slova. Skryté konstruktory tříd jsou:

  • Nezahrnut do výchozího výstupu pro třídu.
  • Součástí seznamu členů třídy vrácených rutinou Get-Member není. Pokud chcete zobrazit skryté vlastnosti pomocí Get-Memberparametru Force .
  • Nezobrazuje se v dokončování tabulátoru nebo IntelliSense, pokud nedojde k dokončení ve třídě, která definuje skrytou vlastnost.
  • Veřejné členy třídy. K nim je možné přistupovat a upravovat. Skrytí vlastnosti ho neudělá jako soukromou. Skryje vlastnost, jak je popsáno v předchozích bodech.

Poznámka:

Když skryjete jakýkoli konstruktor, new() možnost se odebere z IntelliSense a výsledků dokončení.

Další informace o klíčovém slově hidden najdete v tématu about_Hidden.

Statické konstruktory

Konstruktor můžete definovat jako patřící do samotné třídy místo instancí třídy deklarací konstruktoru s klíčovým slovem static . Statické konstruktory tříd:

  • Vyvolání pouze při prvním vytvoření instance třídy v relaci.
  • Nemůže mít žádné parametry.
  • Nelze získat přístup k vlastnostem instance nebo metodám s proměnnou $this .

Konstruktory pro odvozené třídy

Když třída dědí z jiné třídy, konstruktory 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.

Příklad konstruktorů v odvozené třídě naleznete v příkladu 5.

Řetězení konstruktorů

Na rozdíl od jazyka C# nemůžou konstruktory tříd PowerShellu : this(<parameters>) používat řetězení se syntaxí. Chcete-li omezit duplikaci kódu, použijte skrytou Init() metodu s více přetíženími na stejný účinek. Příklad 4 ukazuje třídu používající tento vzor.

Přidání vlastností a metod instance pomocí Update-TypeData

Kromě deklarování vlastností a metod přímo v definici třídy můžete definovat vlastnosti pro instance třídy ve statickém konstruktoru pomocí rutiny Update-TypeData .

Tento fragment kódu použijte jako výchozí bod pro vzor. Podle potřeby nahraďte zástupný text v úhlových závorkách.

class <class-name> {
    static [hashtable[]] $MemberDefinitions = @(
        @{
            Name       = '<member-name>'
            MemberType = '<member-type>'
            Value      = <member-definition>
        }
    )

    static <class-name>() {
        $TypeName = [<class-name>].Name
        foreach ($Definition in [<class-name>]::MemberDefinitions) {
            Update-TypeData -TypeName $TypeName @Definition
        }
    }
}

Tip

Rutina Add-Member může přidat vlastnosti a metody do třídy v nestatického konstruktoru, ale rutina se spustí při každém zavolání konstruktoru. Použití Update-TypeData ve statickém konstruktoru zajišťuje, že kód pro přidání členů do třídy musí běžet pouze jednou v relaci.

Pouze přidat vlastnosti do třídy v nestatické konstruktory, pokud nelze definovat pomocí Update-TypeData, jako jsou vlastnosti jen pro čtení.

Další informace o definování metod instance pomocí Update-TypeDatanaleznete v tématu about_Classes_Methods. Další informace o definování vlastností instance pomocí Update-TypeDatanaleznete v tématu about_Classes_Properties.

Omezení

Konstruktory tříd PowerShellu mají následující omezení:

  • Řetězení konstruktorů není implementováno.

    Alternativní řešení: Definujte skryté Init() metody a volejte je z konstruktorů.

  • Parametry konstruktoru nemohou používat žádné atributy, včetně ověřovacích atributů.

    Alternativní řešení: Přeřaďte parametry v těle konstruktoru pomocí ověřovacího atributu.

  • Parametry konstruktoru nemůžou definovat výchozí hodnoty. Parametry jsou vždy povinné.

    Řešení: Žádné.

  • Pokud je jakékoli přetížení konstruktoru skryté, je každé přetížení konstruktoru považováno za skryté.

    Řešení: Žádné.

Viz také