Share via


about_Classes_Constructors

Descrizione breve

Descrive come definire i costruttori per le classi di PowerShell.

Descrizione lunga

I costruttori consentono di impostare i valori predefiniti e convalidare la logica dell'oggetto al momento della creazione dell'istanza della classe . I costruttori hanno lo stesso nome della classe . I costruttori possono avere parametri per inizializzare i membri dati del nuovo oggetto.

I costruttori di classi di PowerShell sono definiti come metodi speciali nella classe . Si comportano come i metodi della classe PowerShell con le eccezioni seguenti:

  • I costruttori non hanno un tipo di output. Non possono usare la return parola chiave .
  • I costruttori hanno sempre lo stesso nome della classe .
  • I costruttori non possono essere chiamati direttamente. Vengono eseguiti solo quando viene creata un'istanza di .
  • I costruttori non vengono mai visualizzati nell'output per il Get-Member cmdlet .

Per altre informazioni sui metodi della classe PowerShell, vedere about_Classes_Methods.

La classe può avere zero o più costruttori definiti. Se non viene definito alcun costruttore, alla classe viene assegnato un costruttore senza parametri predefinito. Questo costruttore inizializza tutti i membri con i relativi valori predefiniti. Ai tipi di oggetto e alle stringhe vengono assegnati valori Null. Quando si definisce il costruttore, non viene creato alcun costruttore senza parametri predefinito. Creare un costruttore senza parametri, se necessario.

È anche possibile definire un costruttore statico senza parametri.

Sintassi

I costruttori di classi usano le sintassi seguenti:

Sintassi del costruttore predefinita

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

Sintassi del costruttore statico

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

Sintassi del costruttore con parametri (una riga)

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

Sintassi del costruttore con parametri (multilinea)

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

Esempi

Esempio 1- Definizione di una classe con il costruttore predefinito

La classe ExampleBook1 non definisce un costruttore. Usa invece il costruttore predefinito automatico.

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

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

Nota

Il valore predefinito per le proprietà Name e Author è $null dovuto al fatto che vengono digitati come stringhe, ovvero un tipo riferimento. Le altre proprietà hanno il valore predefinito per il tipo definito, perché sono proprietà del tipo valore. Per altre informazioni sui valori predefiniti per le proprietà, vedere "Valori delle proprietà predefinite" in about_Classes_Properties.

Esempio 2- Override del costruttore predefinito

ExampleBook2 definisce in modo esplicito il costruttore predefinito, impostando i valori per PublishedOn sulla data corrente e su Pages su 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

Esempio 3 - Definizione degli overload del costruttore

La classe ExampleBook3 definisce tre overload del costruttore, consentendo agli utenti di creare un'istanza della classe da una tabella hash, passando ogni valore della proprietà e passando il nome del libro e dell'autore. La classe non definisce il costruttore predefinito.

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

La chiamata al costruttore predefinito restituisce un'eccezione del metodo. Il costruttore predefinito automatico è definito solo per una classe quando la classe non definisce costruttori. Poiché ExampleBook3 definisce più overload, il costruttore predefinito non viene aggiunto automaticamente alla classe .

Esempio 4 - Concatenamento di costruttori con un metodo condiviso

In questo esempio viene illustrato come scrivere codice condiviso riutilizzabile per i costruttori. Le classi di PowerShell non possono usare il concatenamento dei costruttori, quindi questa classe di esempio definisce invece un Init() metodo. Il metodo dispone di diversi overload. Gli overload con un minor numero di parametri chiamano gli overload più espliciti con valori predefiniti per i parametri non specificati.

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

Esempio 5 - Costruttori di classi derivate

Negli esempi seguenti vengono usate classi che definiscono i costruttori statici, predefiniti e con parametri per una classe base e una classe derivata che eredita dalla classe base.

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

Il blocco seguente mostra la messaggistica dettagliata per chiamare i costruttori della classe di base. Il messaggio del costruttore statico viene generato solo la prima volta che viene creata un'istanza della classe .

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)

Il blocco successivo mostra la messaggistica dettagliata per chiamare i costruttori della classe derivata in una nuova sessione. La prima volta che viene chiamato un costruttore di classe derivata, vengono chiamati i costruttori statici per la classe base e la classe derivata. Questi costruttori non vengono chiamati di nuovo nella sessione. I costruttori per la classe base vengono sempre eseguiti prima dei costruttori per la classe derivata.

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)

Ordinamento dell'esecuzione del costruttore

Quando viene creata un'istanza di una classe, viene eseguito il codice per uno o più costruttori.

Per le classi che non ereditano da un'altra classe, l'ordinamento è:

  1. Costruttore statico per la classe .
  2. Overload del costruttore applicabile per la classe .

Per le classi derivate che ereditano da un'altra classe, l'ordinamento è:

  1. Costruttore statico per la classe base.
  2. Costruttore statico per la classe derivata.
  3. Se il costruttore della classe derivata chiama in modo esplicito un overload del costruttore di base, esegue tale costruttore per la classe base. Se non chiama in modo esplicito un costruttore di base, esegue il costruttore predefinito per la classe base.
  4. Overload del costruttore applicabile per la classe derivata.

In tutti i casi, i costruttori statici vengono eseguiti una sola volta in una sessione.

Per un esempio di comportamento e ordinamento del costruttore, vedere Esempio 5.

Costruttori nascosti

È possibile nascondere i costruttori di una classe dichiarandoli con la hidden parola chiave . I costruttori di classi nascosti sono:

  • Non incluso nell'output predefinito per la classe .
  • Non incluso nell'elenco dei membri della classe restituiti dal Get-Member cmdlet . Per visualizzare le proprietà nascoste con Get-Member, usare il parametro Force .
  • Non visualizzato in completamento tramite tabulazione o IntelliSense, a meno che il completamento non si verifichi nella classe che definisce la proprietà nascosta.
  • Membri pubblici della classe . È possibile accedervi e modificarli. Nascondere una proprietà non lo rende privato. Nasconde solo la proprietà come descritto nei punti precedenti.

Nota

Quando si nasconde un costruttore, l'opzione new() viene rimossa da IntelliSense e dai risultati di completamento.

Per altre informazioni sulla hidden parola chiave, vedere about_Hidden.

Costruttori statici

È possibile definire un costruttore come appartenente alla classe stessa anziché a istanze della classe dichiarando il costruttore con la static parola chiave . Costruttori di classi statiche:

  • Richiamare solo la prima volta che viene creata un'istanza della classe nella sessione.
  • Non può avere parametri.
  • Non è possibile accedere alle proprietà o ai metodi dell'istanza con la $this variabile .

Costruttori per le classi derivate

Quando una classe eredita da un'altra classe, i costruttori possono richiamare un costruttore dalla classe base con la base parola chiave . Se la classe derivata non richiama in modo esplicito un costruttore dalla classe base, richiama invece il costruttore predefinito per la classe base.

Per richiamare un costruttore di base non predefinito, aggiungere : base(<parameters>) dopo i parametri del costruttore e prima del blocco del corpo.

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

Quando si definisce un costruttore che chiama un costruttore di classe base, i parametri possono essere uno degli elementi seguenti:

  • Variabile di qualsiasi parametro nel costruttore della classe derivata.
  • Qualsiasi valore statico.
  • Qualsiasi espressione che restituisce un valore del tipo di parametro.

Per un esempio di costruttori in una classe derivata, vedere Esempio 5.

Concatenamento dei costruttori

A differenza di C#, i costruttori di classi di PowerShell non possono usare il concatenamento con la : this(<parameters>) sintassi. Per ridurre la duplicazione del codice, usare un metodo nascosto Init() con più overload allo stesso effetto. L'esempio 4 mostra una classe che usa questo modello.

Aggiunta di proprietà e metodi dell'istanza con Update-TypeData

Oltre a dichiarare proprietà e metodi direttamente nella definizione della classe, è possibile definire le proprietà per le istanze di una classe nel costruttore statico usando il Update-TypeData cmdlet .

Usare questo frammento di codice come punto di partenza per il modello. Sostituire il testo segnaposto tra parentesi angolari in base alle esigenze.

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

Suggerimento

Il Add-Member cmdlet può aggiungere proprietà e metodi a una classe in costruttori non statici, ma il cmdlet viene eseguito ogni volta che viene chiamato il costruttore. L'uso Update-TypeData nel costruttore statico garantisce che il codice per l'aggiunta dei membri alla classe debba essere eseguito una sola volta in una sessione.

Aggiungere proprietà alla classe solo in costruttori non statici quando non possono essere definite con Update-TypeData, ad esempio le proprietà di sola lettura.

Per altre informazioni sulla definizione dei metodi di istanza con Update-TypeData, vedere about_Classes_Methods. Per altre informazioni sulla definizione delle proprietà dell'istanza con Update-TypeData, vedere about_Classes_Properties.

Limiti

I costruttori di classi di PowerShell presentano le limitazioni seguenti:

  • Il concatenamento del costruttore non è implementato.

    Soluzione alternativa: definire i metodi nascosti Init() e chiamarli dall'interno dei costruttori.

  • I parametri del costruttore non possono usare attributi, inclusi gli attributi di convalida.

    Soluzione alternativa: riassegnare i parametri nel corpo del costruttore con l'attributo di convalida.

  • I parametri del costruttore non possono definire i valori predefiniti. I parametri sono sempre obbligatori.

    Soluzione alternativa: nessuna.

  • Se un overload di un costruttore è nascosto, ogni overload per il costruttore viene considerato anche nascosto.

    Soluzione alternativa: nessuna.

Vedi anche