about_Classes_Constructors

Krótki opis

Opisuje sposób definiowania konstruktorów dla klas programu PowerShell.

Długi opis

Konstruktory umożliwiają ustawianie wartości domyślnych i weryfikowanie logiki obiektu w momencie tworzenia wystąpienia klasy. Konstruktory mają taką samą nazwę jak klasa. Konstruktory mogą mieć parametry, aby zainicjować elementy członkowskie danych nowego obiektu.

Konstruktory klas programu PowerShell są definiowane jako specjalne metody w klasie. Zachowują się tak samo jak metody klas programu PowerShell z następującymi wyjątkami:

  • Konstruktory nie mają typu danych wyjściowych. Nie mogą używać słowa kluczowego return .
  • Konstruktory zawsze mają taką samą nazwę jak klasa.
  • Konstruktory nie mogą być wywoływane bezpośrednio. Są one uruchamiane tylko po utworzeniu wystąpienia.
  • Konstruktory nigdy nie pojawiają się w danych wyjściowych polecenia Get-Member cmdlet.

Aby uzyskać więcej informacji na temat metod klas programu PowerShell, zobacz about_Classes_Methods.

Klasa może mieć zdefiniowany zero lub więcej konstruktorów. Jeśli żaden konstruktor nie jest zdefiniowany, klasa otrzymuje domyślny konstruktor bez parametrów. Ten konstruktor inicjuje wszystkie elementy członkowskie do ich wartości domyślnych. Typy obiektów i ciągi mają wartości null. Podczas definiowania konstruktora nie jest tworzony domyślny konstruktor bez parametrów. Utwórz konstruktor bez parametrów, jeśli jest potrzebny.

Można również zdefiniować konstruktor statyczny bez parametrów.

Składnia

Konstruktory klas używają następujących składni:

Domyślna składnia konstruktora

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

Składnia konstruktora statycznego

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

Składnia konstruktora sparametryzowanego (jednowierszowa)

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

Składnia konstruktora sparametryzowanego (wielowierszowa)

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

Przykłady

Przykład 1 — Definiowanie klasy za pomocą konstruktora domyślnego

Klasa ExampleBook1 nie definiuje konstruktora. Zamiast tego używa automatycznego konstruktora domyślnego.

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

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

Uwaga

Wartością domyślną właściwości Name (Nazwa ) i Author (Autor ) jest $null to, że są one wpisywane jako ciągi, czyli typ odwołania. Inne właściwości mają wartość domyślną dla zdefiniowanego typu, ponieważ są właściwościami typu wartości. Aby uzyskać więcej informacji na temat wartości domyślnych właściwości, zobacz "Domyślne wartości właściwości" w about_Classes_Properties.

Przykład 2 — zastępowanie konstruktora domyślnego

ExampleBook2 jawnie definiuje konstruktor domyślny, ustawiając wartości właściwości PublishedOn na bieżącą datę, a wartość 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

Przykład 3 — Definiowanie przeciążeń konstruktora

Klasa ExampleBook3 definiuje trzy przeciążenia konstruktora, umożliwiając użytkownikom tworzenie wystąpienia klasy na podstawie tabeli skrótu, przekazując każdą wartość właściwości i przekazując nazwę książki i autora. Klasa nie definiuje konstruktora domyślnego.

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

Wywołanie konstruktora domyślnego zwraca wyjątek metody. Automatyczny konstruktor domyślny jest definiowany tylko dla klasy, gdy klasa nie definiuje żadnych konstruktorów. Ponieważ ExampleBook3 definiuje wiele przeciążeń, domyślny konstruktor nie jest automatycznie dodawany do klasy.

Przykład 4 — Łączenie konstruktorów z udostępnioną metodą

W tym przykładzie pokazano, jak można napisać kod udostępniony wielokrotnego użytku dla konstruktorów. Klasy programu PowerShell nie mogą używać łańcucha konstruktorów, więc ta przykładowa klasa definiuje metodę Init() . Metoda ma kilka przeciążeń. Przeciążenia z mniejszą liczbą parametrów wywołają bardziej jawne przeciążenia z wartościami domyślnymi dla nieokreślonych parametrów.

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

Przykład 5 — konstruktory klas pochodnych

W poniższych przykładach użyto klas definiujących konstruktory statyczne, domyślne i sparametryzowane dla klasy bazowej oraz klasy pochodnej dziedziczącej z klasy bazowej.

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

Poniższy blok przedstawia pełne komunikaty służące do wywoływania konstruktorów klasy bazowej. Komunikat konstruktora statycznego jest emitowany tylko przy pierwszym utworzeniu wystąpienia klasy.

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)

Następny blok przedstawia pełne komunikaty służące do wywoływania konstruktorów klasy pochodnej w nowej sesji. Przy pierwszym wywołaniu konstruktora klasy pochodnej wywoływane są konstruktory statyczne dla klasy bazowej i klasy pochodnej. Te konstruktory nie są ponownie wywoływane w sesji. Konstruktory klasy bazowej są zawsze uruchamiane przed konstruktorami klasy pochodnej.

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)

Porządkowanie przebiegu konstruktora

Gdy wystąpi wystąpienie klasy, wykonywany jest kod dla co najmniej jednego konstruktora.

W przypadku klas, które nie dziedziczą z innej klasy, kolejność to:

  1. Konstruktor statyczny dla klasy.
  2. Odpowiednie przeciążenie konstruktora dla klasy.

W przypadku klas pochodnych dziedziczącej z innej klasy kolejność to:

  1. Konstruktor statyczny dla klasy bazowej.
  2. Konstruktor statyczny dla klasy pochodnej.
  3. Jeśli konstruktor klasy pochodnej jawnie wywołuje przeciążenie konstruktora podstawowego, uruchamia ten konstruktor dla klasy bazowej. Jeśli nie wywołuje jawnie konstruktora podstawowego, uruchamia domyślny konstruktor dla klasy bazowej.
  4. Odpowiednie przeciążenie konstruktora dla klasy pochodnej.

We wszystkich przypadkach konstruktory statyczne są uruchamiane tylko raz w sesji.

Aby zapoznać się z przykładem zachowania i kolejności konstruktora, zobacz Przykład 5.

Konstruktory ukryte

Konstruktory klasy można ukryć, deklarując je za pomocą słowa kluczowego hidden . Ukryte konstruktory klas to:

  • Nieuwzględniane w domyślnych danych wyjściowych klasy.
  • Nieuwzględniane na liście składowych klas zwracanych przez Get-Member polecenie cmdlet. Aby wyświetlić ukryte właściwości za pomocą Get-Memberpolecenia , użyj parametru Force .
  • Nie są wyświetlane w uzupełnianiu tabulatora lub funkcji IntelliSense, chyba że ukończenie występuje w klasie definiującej właściwość ukrytą.
  • Publiczne elementy członkowskie klasy. Dostęp do nich można uzyskać i zmodyfikować. Ukrywanie właściwości nie powoduje, że jest ona prywatna. Ukrywa tylko właściwość zgodnie z opisem w poprzednich punktach.

Uwaga

Po ukryciu dowolnego konstruktora new() opcja zostanie usunięta z funkcji IntelliSense i wyników ukończenia.

Aby uzyskać więcej informacji na temat słowa kluczowego hidden , zobacz about_Hidden.

Konstruktory statyczne

Konstruktor można zdefiniować jako należący do samej klasy zamiast wystąpień klasy, deklarując konstruktor za pomocą słowa kluczowego static . Konstruktory klas statycznych:

  • Wywołaj tylko pierwsze wystąpienie klasy jest tworzone w sesji.
  • Nie można mieć żadnych parametrów.
  • Nie można uzyskać dostępu do właściwości lub metod wystąpienia za pomocą zmiennej $this .

Konstruktory dla klas pochodnych

Gdy klasa dziedziczy z innej klasy, konstruktory mogą wywoływać konstruktor z klasy bazowej za pomocą słowa kluczowego base . Jeśli klasa pochodna nie wywołuje jawnie konstruktora z klasy bazowej, wywołuje zamiast tego konstruktor domyślny dla klasy bazowej.

Aby wywołać konstruktor podstawowy bez definicji, dodaj : base(<parameters>) po parametrach konstruktora i przed blokiem treści.

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

Podczas definiowania konstruktora, który wywołuje konstruktor klasy bazowej, parametry mogą być dowolnym z następujących elementów:

  • Zmienna dowolnego parametru w konstruktorze klasy pochodnej.
  • Dowolna wartość statyczna.
  • Dowolne wyrażenie, które oblicza wartość typu parametru.

Przykład konstruktorów w klasie pochodnej można znaleźć w przykładzie 5.

Konstruktory łańcuchowe

W przeciwieństwie do języka C#, konstruktory klas programu PowerShell nie mogą używać łączenia łańcuchów ze składnią : this(<parameters>) . Aby zmniejszyć duplikację kodu, użyj ukrytej Init() metody z wieloma przeciążeniami w tym samym efekcie. Przykład 4 przedstawia klasę używającą tego wzorca.

Dodawanie właściwości i metod wystąpienia za pomocą metody Update-TypeData

Poza deklarowaniem właściwości i metod bezpośrednio w definicji klasy można zdefiniować właściwości dla wystąpień klasy w konstruktorze statycznym przy użyciu Update-TypeData polecenia cmdlet .

Użyj tego fragmentu kodu jako punktu wyjścia dla wzorca. Zastąp tekst zastępczy w nawiasach kątowych zgodnie z potrzebami.

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

Napiwek

Polecenie Add-Member cmdlet może dodawać właściwości i metody do klasy w konstruktorach niestacjonanych, ale polecenie cmdlet jest uruchamiane za każdym razem, gdy konstruktor jest wywoływany. Użycie Update-TypeData w konstruktorze statycznym gwarantuje, że kod dodawania składowych do klasy musi być uruchamiany tylko raz w sesji.

Dodaj właściwości tylko do klasy w konstruktorach niestacjonanych, gdy nie można ich zdefiniować za pomocą Update-TypeDatawłaściwości , takich jak właściwości tylko do odczytu.

Aby uzyskać więcej informacji na temat definiowania metod wystąpień za pomocą Update-TypeDataprogramu , zobacz about_Classes_Methods. Aby uzyskać więcej informacji na temat definiowania właściwości wystąpienia za pomocą Update-TypeDataprogramu , zobacz about_Classes_Properties.

Ograniczenia

Konstruktory klas programu PowerShell mają następujące ograniczenia:

  • Łańcuch konstruktora nie jest implementowany.

    Obejście: Zdefiniuj ukryte Init() metody i wywołaj je z poziomu konstruktorów.

  • Parametry konstruktora nie mogą używać żadnych atrybutów, w tym atrybutów walidacji.

    Obejście: Przypisz ponownie parametry w treści konstruktora za pomocą atrybutu weryfikacji.

  • Parametry konstruktora nie mogą definiować wartości domyślnych. Parametry są zawsze obowiązkowe.

    Obejście: brak.

  • Jeśli jakiekolwiek przeciążenie konstruktora jest ukryte, każde przeciążenie konstruktora jest również traktowane jako ukryte.

    Obejście: brak.

Zobacz też