about_Classes

Krótki opis

Opisuje sposób używania klas do tworzenia własnych typów niestandardowych.

Długi opis

Począwszy od wersji 5.0, program PowerShell ma formalną składnię do definiowania klas i innych typów zdefiniowanych przez użytkownika. Dodanie klas umożliwia deweloperom i specjalistom IT korzystanie z programu PowerShell w szerszym zakresie przypadków użycia.

Deklaracja klasy jest strategią używaną do tworzenia wystąpień obiektów w czasie wykonywania. Podczas definiowania klasy nazwa klasy jest nazwą typu. Jeśli na przykład zadeklarujesz klasę o nazwie Device i zainicjujesz zmienną $dev do nowego wystąpienia urządzenia, $dev jest obiektem lub wystąpieniem typu Urządzenie. Każde wystąpienie urządzenia może mieć różne wartości we właściwościach.

Obsługiwane scenariusze

  • Definiowanie typów niestandardowych w programie PowerShell przy użyciu semantyki programowania obiektowego, takich jak klasy, właściwości, metody, dziedziczenie itp.
  • Zdefiniuj zasoby DSC i skojarzone z nimi typy przy użyciu języka programu PowerShell.
  • Zdefiniuj atrybuty niestandardowe do dekorowania zmiennych, parametrów i niestandardowych definicji typów.
  • Zdefiniuj niestandardowe wyjątki, które mogą być przechwytywane przez ich nazwę typu.

Składnia

Składnia definicji

Definicje klas używają następującej składni:

class <class-name> [: [<base-class>][,<interface-list>]] {
    [[<attribute>] [hidden] [static] <property-definition> ...]
    [<class-name>([<constructor-argument-list>])
      {<constructor-statement-list>} ...]
    [[<attribute>] [hidden] [static] <method-definition> ...]
}

Składnia wystąpienia

Aby utworzyć wystąpienie klasy, użyj jednej z następujących składni:

[$<variable-name> =] New-Object -TypeName <class-name> [
  [-ArgumentList] <constructor-argument-list>]
[$<variable-name> =] [<class-name>]::new([<constructor-argument-list>])
[$<variable-name> =] [<class-name>]@{[<class-property-hashtable>]}

Uwaga

W przypadku używania [<class-name>]::new() składni nawiasy wokół nazwy klasy są obowiązkowe. Nawiasy sygnalizujące definicję typu dla programu PowerShell.

Składnia skrótu działa tylko dla klas, które mają konstruktor domyślny, który nie oczekuje żadnych parametrów. Tworzy wystąpienie klasy z konstruktorem domyślnym, a następnie przypisuje pary klucz-wartość do właściwości wystąpienia. Jeśli jakikolwiek klucz w tabeli skrótu nie jest prawidłową nazwą właściwości, program PowerShell zgłasza błąd.

Przykłady

Przykład 1 — minimalna definicja

W tym przykładzie przedstawiono minimalną składnię wymaganą do utworzenia klasy użytecznej.

class Device {
    [string]$Brand
}

$dev = [Device]::new()
$dev.Brand = "Fabrikam, Inc."
$dev
Brand
-----
Fabrikam, Inc.

Przykład 2 — Klasa z elementami członkowskimi wystąpienia

W tym przykładzie zdefiniowano klasę Book z kilkoma właściwościami, konstruktorami i metodami. Każdy zdefiniowany element członkowski jest członkiem wystąpienia , a nie statycznym elementem członkowskim. Dostęp do właściwości i metod można uzyskać tylko za pośrednictwem utworzonego wystąpienia klasy.

class Book {
    # Class properties
    [string]   $Title
    [string]   $Author
    [string]   $Synopsis
    [string]   $Publisher
    [datetime] $PublishDate
    [int]      $PageCount
    [string[]] $Tags
    # Default constructor
    Book() { $this.Init(@{}) }
    # Convenience constructor from hashtable
    Book([hashtable]$Properties) { $this.Init($Properties) }
    # Common constructor for title and author
    Book([string]$Title, [string]$Author) {
        $this.Init(@{Title = $Title; Author = $Author })
    }
    # Shared initializer method
    [void] Init([hashtable]$Properties) {
        foreach ($Property in $Properties.Keys) {
            $this.$Property = $Properties.$Property
        }
    }
    # Method to calculate reading time as 2 minutes per page
    [timespan] GetReadingTime() {
        if ($this.PageCount -le 0) {
            throw 'Unable to determine reading time from page count.'
        }
        $Minutes = $this.PageCount * 2
        return [timespan]::new(0, $Minutes, 0)
    }
    # Method to calculate how long ago a book was published
    [timespan] GetPublishedAge() {
        if (
            $null -eq $this.PublishDate -or
            $this.PublishDate -eq [datetime]::MinValue
        ) { throw 'PublishDate not defined' }

        return (Get-Date) - $this.PublishDate
    }
    # Method to return a string representation of the book
    [string] ToString() {
        return "$($this.Title) by $($this.Author) ($($this.PublishDate.Year))"
    }
}

Poniższy fragment kodu tworzy wystąpienie klasy i pokazuje, jak się zachowuje. Po utworzeniu wystąpienia klasy Book przykład używa GetReadingTime() metod i GetPublishedAge() do pisania komunikatu o książce.

$Book = [Book]::new(@{
    Title       = 'The Hobbit'
    Author      = 'J.R.R. Tolkien'
    Publisher   = 'George Allen & Unwin'
    PublishDate = '1937-09-21'
    PageCount   = 310
    Tags        = @('Fantasy', 'Adventure')
})

$Book
$Time = $Book.GetReadingTime()
$Time = @($Time.Hours, 'hours and', $Time.Minutes, 'minutes') -join ' '
$Age  = [Math]::Floor($Book.GetPublishedAge().TotalDays / 365.25)

"It takes $Time to read $Book,`nwhich was published $Age years ago."
Title       : The Hobbit
Author      : J.R.R. Tolkien
Synopsis    :
Publisher   : George Allen & Unwin
PublishDate : 9/21/1937 12:00:00 AM
PageCount   : 310
Tags        : {Fantasy, Adventure}

It takes 10 hours and 20 minutes to read The Hobbit by J.R.R. Tolkien (1937),
which was published 86 years ago.

Przykład 3 — Klasa ze statycznymi elementami członkowskimi

Klasa BookList w tym przykładzie opiera się na klasie Book w przykładzie 2. Chociaż klasa BookList nie może być oznaczona jako statyczna, implementacja definiuje tylko właściwość statyczną Books i zestaw metod statycznych do zarządzania tą właściwością.

class BookList {
    # Static property to hold the list of books
    static [System.Collections.Generic.List[Book]] $Books
    # Static method to initialize the list of books. Called in the other
    # static methods to avoid needing to explicit initialize the value.
    static [void] Initialize()             { [BookList]::Initialize($false) }
    static [bool] Initialize([bool]$force) {
        if ([BookList]::Books.Count -gt 0 -and -not $force) {
            return $false
        }

        [BookList]::Books = [System.Collections.Generic.List[Book]]::new()

        return $true
    }
    # Ensure a book is valid for the list.
    static [void] Validate([book]$Book) {
        $Prefix = @(
            'Book validation failed: Book must be defined with the Title,'
            'Author, and PublishDate properties, but'
        ) -join ' '
        if ($null -eq $Book) { throw "$Prefix was null" }
        if ([string]::IsNullOrEmpty($Book.Title)) {
            throw "$Prefix Title wasn't defined"
        }
        if ([string]::IsNullOrEmpty($Book.Author)) {
            throw "$Prefix Author wasn't defined"
        }
        if ([datetime]::MinValue -eq $Book.PublishDate) {
            throw "$Prefix PublishDate wasn't defined"
        }
    }
    # Static methods to manage the list of books.
    # Add a book if it's not already in the list.
    static [void] Add([Book]$Book) {
        [BookList]::Initialize()
        [BookList]::Validate($Book)
        if ([BookList]::Books.Contains($Book)) {
            throw "Book '$Book' already in list"
        }

        $FindPredicate = {
            param([Book]$b)

            $b.Title -eq $Book.Title -and
            $b.Author -eq $Book.Author -and
            $b.PublishDate -eq $Book.PublishDate
        }.GetNewClosure()
        if ([BookList]::Books.Find($FindPredicate)) {
            throw "Book '$Book' already in list"
        }

        [BookList]::Books.Add($Book)
    }
    # Clear the list of books.
    static [void] Clear() {
      [BookList]::Initialize()
      [BookList]::Books.Clear()
    }
    # Find a specific book using a filtering scriptblock.
    static [Book] Find([scriptblock]$Predicate) {
        [BookList]::Initialize()
        return [BookList]::Books.Find($Predicate)
    }
    # Find every book matching the filtering scriptblock.
    static [Book[]] FindAll([scriptblock]$Predicate) {
        [BookList]::Initialize()
        return [BookList]::Books.FindAll($Predicate)
    }
    # Remove a specific book.
    static [void] Remove([Book]$Book) {
        [BookList]::Initialize()
        [BookList]::Books.Remove($Book)
    }
    # Remove a book by property value.
    static [void] RemoveBy([string]$Property, [string]$Value) {
        [BookList]::Initialize()
        $Index = [BookList]::Books.FindIndex({
            param($b)
            $b.$Property -eq $Value
        }.GetNewClosure())
        if ($Index -ge 0) {
            [BookList]::Books.RemoveAt($Index)
        }
    }
}

Teraz, gdy lista BookList jest zdefiniowana, do listy można dodać książkę z poprzedniego przykładu.

$null -eq [BookList]::Books

[BookList]::Add($Book)

[BookList]::Books
True

Title       : The Hobbit
Author      : J.R.R. Tolkien
Synopsis    :
Publisher   : George Allen & Unwin
PublishDate : 9/21/1937 12:00:00 AM
PageCount   : 310
Tags        : {Fantasy, Adventure}

Poniższy fragment kodu wywołuje metody statyczne dla klasy.

[BookList]::Add([Book]::new(@{
    Title       = 'The Fellowship of the Ring'
    Author      = 'J.R.R. Tolkien'
    Publisher   = 'George Allen & Unwin'
    PublishDate = '1954-07-29'
    PageCount   = 423
    Tags        = @('Fantasy', 'Adventure')
}))

[BookList]::Find({
    param ($b)

    $b.PublishDate -gt '1950-01-01'
}).Title

[BookList]::FindAll({
    param($b)

    $b.Author -match 'Tolkien'
}).Title

[BookList]::Remove($Book)
[BookList]::Books.Title

[BookList]::RemoveBy('Author', 'J.R.R. Tolkien')
"Titles: $([BookList]::Books.Title)"

[BookList]::Add($Book)
[BookList]::Add($Book)
The Fellowship of the Ring

The Hobbit
The Fellowship of the Ring

The Fellowship of the Ring

Titles:

Exception:
Line |
  84 |              throw "Book '$Book' already in list"
     |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Book 'The Hobbit by J.R.R. Tolkien (1937)' already in list

Przykład 4 — definicja klasy z koligacją i bez koligacji Runspace

Metoda ShowRunspaceId() raportów różnych identyfikatorów wątków [UnsafeClass] , ale ten sam identyfikator obszaru uruchamiania. Ostatecznie stan sesji jest uszkodzony, powodując błąd, taki jak Global scope cannot be removed.

# Class definition with Runspace affinity (default behavior)
class UnsafeClass {
    static [object] ShowRunspaceId($val) {
        return [PSCustomObject]@{
            ThreadId   = [Threading.Thread]::CurrentThread.ManagedThreadId
            RunspaceId = [runspace]::DefaultRunspace.Id
        }
    }
}

$unsafe = [UnsafeClass]::new()

while ($true) {
    1..10 | ForEach-Object -Parallel {
        Start-Sleep -ms 100
        ($using:unsafe)::ShowRunspaceId($_)
    }
}

Uwaga

Ten przykład działa w nieskończonej pętli. Naciśnij klawisze Ctrl+C, aby zatrzymać wykonywanie.

Metoda ShowRunspaceId() raportów różnych wątków [SafeClass] i identyfikatorów obszaru uruchomieniowego.

# Class definition with NoRunspaceAffinity attribute
[NoRunspaceAffinity()]
class SafeClass {
    static [object] ShowRunspaceId($val) {
        return [PSCustomObject]@{
            ThreadId   = [Threading.Thread]::CurrentThread.ManagedThreadId
            RunspaceId = [runspace]::DefaultRunspace.Id
        }
    }
}

$safe = [SafeClass]::new()

while ($true) {
    1..10 | ForEach-Object -Parallel {
        Start-Sleep -ms 100
        ($using:safe)::ShowRunspaceId($_)
    }
}

Uwaga

Ten przykład działa w nieskończonej pętli. Naciśnij klawisze Ctrl+C, aby zatrzymać wykonywanie.

Właściwości klasy

Właściwości to zmienne zadeklarowane w zakresie klasy. Właściwość może mieć dowolny typ wbudowany lub wystąpienie innej klasy. Klasy mogą mieć zero lub więcej właściwości. Klasy nie mają maksymalnej liczby właściwości.

Aby uzyskać więcej informacji, zobacz about_Classes_Properties.

Metody klas

Metody definiują akcje, które może wykonywać klasa. Metody mogą przyjmować parametry określające dane wejściowe. Metody zawsze definiują typ danych wyjściowych. Jeśli metoda nie zwraca żadnych danych wyjściowych, musi mieć typ danych wyjściowych Void . Jeśli metoda nie definiuje jawnie typu danych wyjściowych, typ danych wyjściowych metody to Void.

Aby uzyskać więcej informacji, zobacz about_Classes_Methods.

Konstruktory klas

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.

Aby uzyskać więcej informacji, zobacz about_Classes_Constructors.

Ukryte słowo kluczowe

Słowo hidden kluczowe ukrywa składową klasy. Element członkowski jest nadal dostępny dla użytkownika i jest dostępny we wszystkich zakresach, w których obiekt jest dostępny. Ukryte elementy członkowskie są ukryte przed poleceniem Get-Member cmdlet i nie można ich wyświetlić przy użyciu uzupełniania kart ani funkcji IntelliSense poza definicją klasy.

Słowo hidden kluczowe dotyczy tylko składowych klasy, a nie samej klasy.

Ukryte składowe klasy 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 elementy członkowskie za pomocą Get-Memberpolecenia , użyj parametru Force .
  • Nie są wyświetlane w uzupełnianiu karty lub funkcji IntelliSense, chyba że ukończenie występuje w klasie definiującej ukryty element członkowski.
  • Publiczne elementy członkowskie klasy. Można uzyskać do nich dostęp, dziedziczyć i modyfikować. Ukrywanie elementu członkowskiego nie powoduje, że jest on prywatny. Ukrywa on tylko element członkowski zgodnie z opisem w poprzednich punktach.

Uwaga

Po ukryciu przeciążenia metody ta metoda zostanie usunięta z funkcji IntelliSense, wyników ukończenia i domyślnych danych wyjściowych dla metody Get-Member. 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, zobacz about_Hidden. Aby uzyskać więcej informacji na temat ukrytych właściwości, zobacz about_Classes_Properties. Aby uzyskać więcej informacji na temat ukrytych metod, zobacz about_Classes_Methods. Aby uzyskać więcej informacji na temat ukrytych konstruktorów, zobacz about_Classes_Constructors.

Słowo kluczowe statyczne

Słowo static kluczowe definiuje właściwość lub metodę, która istnieje w klasie i nie wymaga wystąpienia.

Właściwość statyczna jest zawsze dostępna, niezależnie od wystąpienia klasy. Właściwość statyczna jest współdzielona we wszystkich wystąpieniach klasy. Metoda statyczna jest zawsze dostępna. Wszystkie właściwości statyczne są aktywne dla całego zakresu sesji.

Słowo static kluczowe dotyczy tylko składowych klasy, a nie samej klasy.

Aby uzyskać więcej informacji na temat właściwości statycznych, zobacz about_Classes_Properties. Aby uzyskać więcej informacji na temat metod statycznych, zobacz about_Classes_Methods. Aby uzyskać więcej informacji na temat konstruktorów statycznych, zobacz about_Classes_Constructors.

Dziedziczenie w klasach programu PowerShell

Klasę można rozszerzyć, tworząc nową klasę pochodzącą z istniejącej klasy. Klasa pochodna dziedziczy właściwości i metody klasy bazowej. Możesz dodać lub zastąpić składowe klasy bazowej zgodnie z wymaganiami.

Program PowerShell nie obsługuje wielu dziedziczenia. Klasy nie mogą dziedziczyć bezpośrednio z więcej niż jednej klasy.

Klasy mogą również dziedziczyć z interfejsów, które definiują kontrakt. Klasa dziedziczona z interfejsu musi implementować ten kontrakt. W takim przypadku klasa może być używana jak każda inna klasa implementujący ten interfejs.

Aby uzyskać więcej informacji na temat klas pochodnych, które dziedziczą z klasy bazowej lub implementują interfejsy, zobacz about_Classes_Inheritance.

Atrybut NoRunspaceAffinity

Przestrzeń uruchomieniowa to środowisko operacyjne poleceń wywoływanych przez program PowerShell. To środowisko zawiera polecenia i dane, które są obecnie obecne, oraz wszelkie ograniczenia języka, które są obecnie stosowane.

Domyślnie klasa programu PowerShell jest powiązana z obszarem Runspace , w którym jest tworzona. Używanie klasy programu PowerShell w programie ForEach-Object -Parallel nie jest bezpieczne. Wywołania metod w klasie są uruchamiane z powrotem do obszaru Runspace , w którym został utworzony, co może uszkodzić stan elementu Runspace lub spowodować zakleszczenie.

Dodanie atrybutu NoRunspaceAffinity do definicji klasy gwarantuje, że klasa programu PowerShell nie jest powiązana z określonym obszarem działania. Wywołania metod, zarówno wystąpienie, jak i statyczne, używają obszaru Runspace uruchomionego wątku i bieżącego stanu sesji wątku.

Atrybut został dodany w programie PowerShell 7.4.

Aby uzyskać ilustrację różnicy w zachowaniu klas z atrybutem i bez atrybutu NoRunspaceAffinity , zobacz Przykład 4.

Eksportowanie klas z akceleratorami typów

Domyślnie moduły programu PowerShell nie eksportują automatycznie klas i wyliczeń zdefiniowanych w programie PowerShell. Typy niestandardowe nie są dostępne poza modułem bez wywoływania instrukcji using module .

Jeśli jednak moduł dodaje akceleratory typów, akceleratory tego typu są natychmiast dostępne w sesji po zaimportowaniu modułu przez użytkowników.

Uwaga

Dodawanie akceleratorów typów do sesji używa wewnętrznego (nie publicznego) interfejsu API. Użycie tego interfejsu API może powodować konflikty. Wzorzec opisany poniżej zgłasza błąd, jeśli akcelerator typu o tej samej nazwie już istnieje podczas importowania modułu. Usuwa również akceleratory typów podczas usuwania modułu z sesji.

Ten wzorzec gwarantuje, że typy są dostępne w sesji. Nie ma to wpływu na funkcję IntelliSense ani uzupełnianie podczas tworzenia pliku skryptu w programie VS Code. Aby uzyskać sugestie dotyczące funkcji IntelliSense i uzupełniania dla typów niestandardowych w programie VS Code, należy dodać instrukcję using module na początku skryptu.

Poniższy wzorzec pokazuje, jak zarejestrować klasy programu PowerShell i wyliczenia jako akceleratory typów w module. Dodaj fragment kodu do modułu skryptu głównego po dowolnych definicjach typów. Upewnij się, że zmienna $ExportableTypes zawiera każdy z typów, które mają być dostępne dla użytkowników podczas importowania modułu. Drugi kod nie wymaga edycji.

# Define the types to export with type accelerators.
$ExportableTypes =@(
    [DefinedTypeName]
)
# Get the internal TypeAccelerators class to use its static methods.
$TypeAcceleratorsClass = [psobject].Assembly.GetType(
    'System.Management.Automation.TypeAccelerators'
)
# Ensure none of the types would clobber an existing type accelerator.
# If a type accelerator with the same name exists, throw an exception.
$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get
foreach ($Type in $ExportableTypes) {
    if ($Type.FullName -in $ExistingTypeAccelerators.Keys) {
        $Message = @(
            "Unable to register type accelerator '$($Type.FullName)'"
            'Accelerator already exists.'
        ) -join ' - '

        throw [System.Management.Automation.ErrorRecord]::new(
            [System.InvalidOperationException]::new($Message),
            'TypeAcceleratorAlreadyExists',
            [System.Management.Automation.ErrorCategory]::InvalidOperation,
            $Type.FullName
        )
    }
}
# Add type accelerators for every exportable type.
foreach ($Type in $ExportableTypes) {
    $TypeAcceleratorsClass::Add($Type.FullName, $Type)
}
# Remove type accelerators when the module is removed.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
    foreach($Type in $ExportableTypes) {
        $TypeAcceleratorsClass::Remove($Type.FullName)
    }
}.GetNewClosure()

Podczas importowania modułu przez użytkowników wszystkie typy dodane do akceleratorów typów dla sesji są natychmiast dostępne dla funkcji IntelliSense i uzupełniania. Po usunięciu modułu są więc akceleratory typów.

Ręczne importowanie klas z modułu programu PowerShell

Import-Module i instrukcja #requires importuje tylko funkcje modułu, aliasy i zmienne, zgodnie z definicją w module. Klasy nie są importowane.

Jeśli moduł definiuje klasy i wyliczenia, ale nie dodaje akceleratorów typów dla tych typów, użyj using module instrukcji , aby je zaimportować.

Instrukcja using module importuje klasy i wyliczenia z modułu głównego (ModuleToProcess) modułu skryptu lub modułu binarnego. Nie importuje spójnie klas zdefiniowanych w zagnieżdżonych modułach ani klasach zdefiniowanych w skryptach, które są dot-source do modułu głównego. Zdefiniuj klasy, które mają być dostępne dla użytkowników spoza modułu bezpośrednio w module głównym.

Aby uzyskać więcej informacji na temat instrukcji using , zobacz about_Using.

Ładowanie nowo zmienionego kodu podczas programowania

Podczas opracowywania modułu skryptu często wprowadza się zmiany w kodzie, a następnie ładują nową wersję modułu przy użyciu Import-Module parametru Force . Ponowne ładowanie modułu działa tylko w przypadku zmian funkcji w module głównym. Import-Module nie ładuje ponownie żadnych zagnieżdżonych modułów. Ponadto nie ma możliwości załadowania zaktualizowanych klas.

Aby upewnić się, że używasz najnowszej wersji, musisz uruchomić nową sesję. Nie można zwolnić klas i wyliczenia zdefiniowanych w programie PowerShell i zaimportowanych za pomocą using instrukcji.

Innym typowym rozwiązaniem programistycznym jest rozdzielenie kodu na różne pliki. Jeśli masz funkcję w jednym pliku, który używa klas zdefiniowanych w innym module, należy użyć using module instrukcji , aby upewnić się, że funkcje mają wymagane definicje klas.

Typ PSReference nie jest obsługiwany z elementami członkowskimi klasy

Akcelerator [ref] typu jest skrótem dla klasy PSReference . Używanie [ref] metody do rzutowania typu składowej klasy kończy się niepowodzeniem w trybie dyskretnym. Interfejsy API używające [ref] parametrów nie mogą być używane z elementami członkowskimi klasy. Klasa PSReference została zaprojektowana do obsługi obiektów COM. Obiekty COM mają przypadki, w których należy przekazać wartość w odwołaniu.

Aby uzyskać więcej informacji, zobacz Klasa PSReference.

Ograniczenia

Poniższe listy zawierają ograniczenia dotyczące definiowania klas programu PowerShell i obejścia tych ograniczeń, jeśli istnieją.

Ogólne ograniczenia

  • Składowe klasy nie mogą używać funkcji PSReference jako ich typu.

    Obejście: brak.

  • Nie można zwolnić ani ponownie załadować klas programu PowerShell w sesji.

    Obejście: Rozpocznij nową sesję.

  • Klasy programu PowerShell zdefiniowane w module nie są importowane automatycznie.

    Obejście: Dodaj zdefiniowane typy do listy akceleratorów typów w module głównym. Dzięki temu typy są dostępne podczas importowania modułów.

  • Słowa hidden kluczowe i static dotyczą tylko składowych klas, a nie definicji klasy.

    Obejście: brak.

  • Domyślnie klasy programu PowerShell nie są bezpieczne do użycia w równoległym wykonywaniu w przestrzeniach uruchamiania. W przypadku wywoływania metod w klasie program PowerShell uruchamia wywołania z powrotem do obszaru Runspace , w którym została utworzona klasa, co może uszkodzić stan elementu Runspace lub spowodować zakleszczenie.

    Obejście: Dodaj NoRunspaceAffinity atrybut do deklaracji klasy.

Ograniczenia konstruktora

  • Ł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.

Ograniczenia metody

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

    Obejście: Przypisz ponownie parametry w treści metody za pomocą atrybutu weryfikacji lub zdefiniuj metodę w konstruktorze statycznym za pomocą Update-TypeData polecenia cmdlet .

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

    Obejście: Zdefiniuj metodę w konstruktorze statycznym za pomocą Update-TypeData polecenia cmdlet .

  • Metody są zawsze publiczne, nawet jeśli są ukryte. Można je przesłonić, gdy klasa jest dziedziczona.

    Obejście: brak.

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

    Obejście: brak.

Ograniczenia właściwości

  • Właściwości statyczne są zawsze modyfikowalne. Klasy programu PowerShell nie mogą definiować niezmiennych właściwości statycznych.

    Obejście: brak.

  • Właściwości nie mogą używać atrybutu ValidateScript , ponieważ argumenty atrybutu właściwości klasy muszą być stałe.

    Obejście: Zdefiniuj klasę dziedziczą z typu ValidateArgumentsAttribute i użyj tego atrybutu.

  • Właściwości zadeklarowane bezpośrednio nie mogą definiować niestandardowych implementacji getter i setter.

    Obejście: Zdefiniuj właściwość ukrytą i użyj polecenia Update-TypeData , aby zdefiniować widoczną logikę pobierania i ustawiania.

  • Właściwości nie mogą używać atrybutu Alias . Atrybut dotyczy tylko parametrów, poleceń cmdlet i funkcji.

    Obejście: Użyj Update-TypeData polecenia cmdlet, aby zdefiniować aliasy w konstruktorach klas.

  • Po przekonwertowaniu klasy programu PowerShell na kod JSON za ConvertTo-Json pomocą polecenia cmdlet dane wyjściowe JSON zawierają wszystkie ukryte właściwości i ich wartości.

    Obejście: brak

Ograniczenia dziedziczenia

  • Program PowerShell nie obsługuje definiowania interfejsów w kodzie skryptu.

    Obejście: Zdefiniuj interfejsy w języku C# i odwołuj się do zestawu, który definiuje interfejsy.

  • Klasy programu PowerShell mogą dziedziczyć tylko z jednej klasy bazowej.

    Obejście: Dziedziczenie klas jest przechodnie. Klasa pochodna może dziedziczyć z innej klasy pochodnej, aby uzyskać właściwości i metody klasy bazowej.

  • Podczas dziedziczenia z klasy ogólnej lub interfejsu należy już zdefiniować parametr typu dla klasy ogólnej. Klasa nie może zdefiniować się jako parametr typu dla klasy lub interfejsu.

    Obejście: Aby pochodzić z ogólnej klasy bazowej lub interfejsu, zdefiniuj typ niestandardowy w innym .psm1 pliku i użyj using module instrukcji , aby załadować typ. Nie ma obejścia dla typu niestandardowego, aby używać go jako parametru typu podczas dziedziczenia po typie ogólnym.

Zobacz też