about_Classes_Constructors

Kort beskrivning

Beskriver hur du definierar konstruktorer för PowerShell-klasser.

Lång beskrivning

Med konstruktorer kan du ange standardvärden och validera objektlogik när du skapar -instansen av klassen. Konstruktorer har samma namn som klassen. Konstruktorer kan ha parametrar för att initiera datamedlemmarna i det nya objektet.

PowerShell-klasskonstruktorer definieras som särskilda metoder för klassen. De beter sig på samma sätt som PowerShell-klassmetoder med följande undantag:

  • Konstruktorer har ingen utdatatyp. De kan inte använda nyckelordet return .
  • Konstruktorer har alltid samma namn som klassen.
  • Konstruktorer kan inte anropas direkt. De körs bara när en instans skapas.
  • Konstruktorer visas aldrig i utdata för cmdleten Get-Member .

Mer information om PowerShell-klassmetoder finns i about_Classes_Methods.

Klassen kan ha noll eller fler konstruktorer definierade. Om ingen konstruktor har definierats får klassen en standardkonstruktor utan parameter. Den här konstruktorn initierar alla medlemmar till deras standardvärden. Objekttyper och strängar får null-värden. När du definierar konstruktorn skapas ingen standardparameterlös konstruktor. Skapa en parameterlös konstruktor om det behövs.

Du kan också definiera en statisk konstruktor utan parametrar.

Syntax

Klasskonstruktorer använder följande syntaxer:

Standardkonstruktorsyntax

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

Syntax för statisk konstruktor

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

Parameteriserad konstruktorsyntax (enrad)

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

Parameteriserad konstruktorsyntax (flera ledningar)

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

Exempel

Exempel 1 – Definiera en klass med standardkonstruktorn

Klassen ExampleBook1 definierar inte någon konstruktor. I stället används den automatiska standardkonstruktorn.

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

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

Kommentar

Standardvärdet för egenskaperna Namn och Författare beror $null på att de skrivs som strängar, vilket är en referenstyp. De andra egenskaperna har standardvärdet för sin definierade typ, eftersom de är värdetypsegenskaper. Mer information om standardvärdena för egenskaper finns i "Standardegenskapsvärden" i about_Classes_Properties.

Exempel 2 – Åsidosätta standardkonstruktorn

ExampleBook2 definierar uttryckligen standardkonstruktorn och anger värdena för PublishedOn till aktuellt datum och Sidor till 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

Exempel 3 – Definiera konstruktoröverlagringar

Klassen ExampleBook3 definierar tre konstruktoröverlagringar, vilket gör det möjligt för användare att skapa en instans av klassen från en hashtable, genom att skicka varje egenskapsvärde och genom att skicka namnet på boken och författaren. Klassen definierar inte standardkonstruktorn.

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".

Om du anropar standardkonstruktorn returneras ett metodfel. Den automatiska standardkonstruktorn definieras bara för en klass när klassen inte definierar några konstruktorer. Eftersom ExampleBook3 definierar flera överlagringar läggs standardkonstruktorn inte automatiskt till i klassen.

Exempel 4 – Länka konstruktorer med en delad metod

Det här exemplet visar hur du kan skriva återanvändbar delad kod för konstruktorer. PowerShell-klasser kan inte använda konstruktorlänkning, så den här exempelklassen definierar en Init() metod i stället. Metoden har flera överlagringar. Överlagringarna med färre parametrar anropar de mer explicita överlagringarna med standardvärden för de ospecificerade parametrarna.

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

Exempel 5 – Härledda klasskonstruktorer

I följande exempel används klasser som definierar statiska konstruktorer, standardkonstruktorer och parameteriserade konstruktorer för en basklass och en härledd klass som ärver från basklassen.

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)
    }
}

Följande block visar utförliga meddelanden för att anropa basklasskonstruktorerna. Det statiska konstruktormeddelandet genereras bara första gången en instans av klassen skapas.

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)

Nästa block visar utförliga meddelanden för att anropa de härledda klasskonstruktorerna i en ny session. Första gången en konstruktor för härledd klass anropas anropas de statiska konstruktorerna för basklassen och den härledda klassen. Dessa konstruktorer anropas inte igen i sessionen. Konstruktorerna för basklassen körs alltid före konstruktorerna för den härledda klassen.

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)

Konstruktorkörningsordning

När en klass instansierar körs koden för en eller flera konstruktorer.

För klasser som inte ärver från en annan klass är ordningen:

  1. Den statiska konstruktorn för klassen.
  2. Den tillämpliga konstruktoröverlagringen för klassen.

För härledda klasser som ärver från en annan klass är ordningen:

  1. Den statiska konstruktorn för basklassen.
  2. Den statiska konstruktorn för den härledda klassen.
  3. Om konstruktorn för den härledda klassen uttryckligen anropar en baskonstruktoröverlagring kör den konstruktorn för basklassen. Om den inte uttryckligen anropar en baskonstruktor kör den standardkonstruktorn för basklassen.
  4. Den tillämpliga konstruktoröverlagringen för den härledda klassen.

I samtliga fall körs statiska konstruktorer bara en gång i en session.

Ett exempel på konstruktorbeteende och ordning finns i Exempel 5.

Dolda konstruktorer

Du kan dölja konstruktorer för en klass genom att deklarera dem med nyckelordet hidden . Dolda klasskonstruktorer är:

  • Ingår inte i standardutdata för klassen.
  • Ingår inte i listan över klassmedlemmar som returneras av cmdleten Get-Member . Om du vill visa dolda egenskaper med Get-Memberanvänder du parametern Force .
  • Visas inte i tabbslut eller IntelliSense om inte slutförandet sker i klassen som definierar den dolda egenskapen.
  • Offentliga medlemmar i klassen. De kan nås och ändras. Att dölja en egenskap gör den inte privat. Den döljer bara egenskapen enligt beskrivningen i föregående punkter.

Kommentar

När du döljer en konstruktor new() tas alternativet bort från IntelliSense och slutföranderesultat.

Mer information om nyckelordet finns i hidden about_Hidden.

Statiska konstruktorer

Du kan definiera en konstruktor som tillhör själva klassen i stället för instanser av klassen genom att deklarera konstruktorn med nyckelordet static . Statiska klasskonstruktorer:

  • Anropa bara första gången en instans av klassen skapas i sessionen.
  • Det går inte att ha några parametrar.
  • Det går inte att komma åt instansegenskaper eller -metoder med variabeln $this .

Konstruktorer för härledda klasser

När en klass ärver från en annan klass kan konstruktorer anropa en konstruktor från basklassen med nyckelordet base . Om den härledda klassen inte uttryckligen anropar en konstruktor från basklassen anropas standardkonstruktorn för basklassen i stället.

Om du vill anropa en nondefault-baskonstruktor lägger du till : base(<parameters>) efter konstruktorparametrarna och före brödtextblocket.

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

När du definierar en konstruktor som anropar en basklasskonstruktor kan parametrarna vara något av följande objekt:

  • Variabeln för valfri parameter i den härledda klasskonstruktorn.
  • Alla statiska värden.
  • Alla uttryck som utvärderas till ett värde av parametertypen.

Ett exempel på konstruktorer i en härledd klass finns i Exempel 5.

Länka konstruktorer

Till skillnad från C# kan PowerShell-klasskonstruktorer inte använda länkning med syntaxen : this(<parameters>) . Om du vill minska koddupliceringen använder du en dold Init() metod med flera överlagringar med samma effekt. Exempel 4 visar en klass med det här mönstret.

Lägga till instansegenskaper och metoder med Update-TypeData

Förutom att deklarera egenskaper och metoder direkt i klassdefinitionen kan du definiera egenskaper för instanser av en klass i den statiska konstruktorn med hjälp av cmdleten Update-TypeData .

Använd det här kodfragmentet som utgångspunkt för mönstret. Ersätt platshållartexten i vinkelparenteser efter behov.

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
        }
    }
}

Dricks

Cmdleten Add-Member kan lägga till egenskaper och metoder i en klass i icke-statiska konstruktorer, men cmdleten körs varje gång konstruktorn anropas. Om du använder Update-TypeData den statiska konstruktorn ser du till att koden för att lägga till medlemmar i klassen bara behöver köras en gång i en session.

Lägg bara till egenskaper i klassen i icke-statiska konstruktorer när de inte kan definieras med Update-TypeData, som skrivskyddade egenskaper.

Mer information om hur du definierar instansmetoder med Update-TypeDatafinns i about_Classes_Methods. Mer information om hur du definierar instansegenskaper med Update-TypeDatafinns i about_Classes_Properties.

Begränsningar

PowerShell-klasskonstruktorer har följande begränsningar:

  • Konstruktorlänkning implementeras inte.

    Lösning: Definiera dolda Init() metoder och anropa dem inifrån konstruktorerna.

  • Konstruktorparametrar kan inte använda några attribut, inklusive valideringsattribut.

    Lösning: Tilldela om parametrarna i konstruktorns brödtext med valideringsattributet.

  • Konstruktorparametrar kan inte definiera standardvärden. Parametrarna är alltid obligatoriska.

    Lösning: Inga.

  • Om någon överlagring av en konstruktor är dold behandlas även varje överlagring för konstruktorn som dold.

    Lösning: Inga.

Se även