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:
- Konstruktor statyczny dla klasy.
- Odpowiednie przeciążenie konstruktora dla klasy.
W przypadku klas pochodnych dziedziczącej z innej klasy kolejność to:
- Konstruktor statyczny dla klasy bazowej.
- Konstruktor statyczny dla klasy pochodnej.
- 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.
- 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-Member
polecenia , 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-TypeData
wł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-TypeData
programu , zobacz about_Classes_Methods. Aby uzyskać więcej informacji na temat definiowania właściwości wystąpienia za pomocą Update-TypeData
programu , 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ż
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla