about_Classes_Inheritance

Deskripsi singkat

Menjelaskan bagaimana Anda dapat menentukan kelas yang memperluas jenis lain.

Deskripsi panjang

Kelas PowerShell mendukung pewarisan, yang memungkinkan Anda menentukan kelas turunan yang menggunakan kembali (mewarisi), memperluas, atau memodifikasi perilaku kelas induk. Kelas yang anggotanya diwarisi disebut kelas dasar. Kelas yang mewarisi anggota kelas dasar disebut kelas turunan.

PowerShell hanya mendukung pewarisan tunggal. Kelas hanya dapat mewarisi dari satu kelas. Namun, warisan bersifat transitif, yang memungkinkan Anda menentukan hierarki warisan untuk sekumpulan jenis. Dengan kata lain, jenis D dapat mewarisi dari tipe C, yang mewarisi dari tipe B, yang mewarisi dari kelas dasar tipe A. Karena pewarisan transitif, anggota tipe A tersedia untuk tipe D.

Kelas turunan tidak mewarisi semua anggota kelas dasar. Anggota berikut ini tidak diwariskan:

  • Konstruktor statis, yang menginisialisasi data statis suatu kelas.
  • Konstruktor instans, yang Anda panggil untuk membuat instans baru dari kelas. Setiap kelas harus mendefinisikan konstruktornya sendiri.

Anda dapat memperluas kelas dengan membuat kelas baru yang berasal dari kelas yang ada. Kelas turunan mewarisi properti dan metode kelas dasar. Anda dapat menambahkan atau mengambil alih anggota kelas dasar sesuai kebutuhan.

Kelas juga dapat mewarisi dari antarmuka, yang menentukan kontrak. Kelas yang mewarisi dari antarmuka harus mengimplementasikan kontrak tersebut. Ketika itu terjadi, kelas dapat digunakan seperti kelas lain yang mengimplementasikan antarmuka tersebut. Jika kelas mewarisi dari antarmuka tetapi tidak mengimplementasikan antarmuka, PowerShell menimbulkan kesalahan penguraian untuk kelas tersebut.

Beberapa operator PowerShell bergantung pada kelas yang menerapkan antarmuka tertentu. Misalnya, -eq operator hanya memeriksa kesetaraan referensi kecuali kelas mengimplementasikan antarmuka System.IEquatable . Operator -le, -lt, -ge, dan -gt hanya bekerja pada kelas yang mengimplementasikan antarmuka System.IComparable .

Kelas turunan : menggunakan sintaks untuk memperluas kelas dasar atau mengimplementasikan antarmuka. Kelas turunan harus selalu tertinggal dalam deklarasi kelas.

Contoh ini memperlihatkan sintaks pewarisan kelas PowerShell dasar.

Class Derived : Base {...}

Contoh ini menunjukkan pewarisan dengan deklarasi antarmuka yang datang setelah kelas dasar.

Class Derived : Base, Interface {...}

Sintaks

Pewarisan kelas menggunakan sintaks berikut:

Sintaks satu baris

class <derived-class-name> : <base-class-or-interface-name>[, <interface-name>...] {
    <derived-class-body>
}

Contohnya:

# Base class only
class Derived : Base {...}
# Interface only
class Derived : System.IComparable {...}
# Base class and interface
class Derived : Base, System.IComparable {...}

Sintaks multibaris

class <derived-class-name> : <base-class-or-interface-name>[,
    <interface-name>...] {
    <derived-class-body>
}

Contohnya:

class Derived : Base,
                System.IComparable,
                System.IFormattable,
                System.IConvertible {
    # Derived class definition
}

Contoh

Contoh 1 - Mewarisi dan mengambil alih dari kelas dasar

Contoh berikut menunjukkan perilaku properti yang diwariskan dengan dan tanpa mengambil alih. Jalankan blok kode secara berurutan setelah membaca deskripsinya.

Menentukan kelas dasar

Blok kode pertama mendefinisikan PublishedWork sebagai kelas dasar. Ini memiliki dua properti statis, Daftar dan Artis. Selanjutnya, ini mendefinisikan metode statis RegisterWork() untuk menambahkan karya ke properti Daftar statis dan artis ke properti Artis, menulis pesan untuk setiap entri baru dalam daftar.

Kelas menentukan tiga properti instans yang menjelaskan pekerjaan yang diterbitkan. Akhirnya, ini mendefinisikan Register() metode instans dan ToString() .

class PublishedWork {
    static [PublishedWork[]] $List    = @()
    static [string[]]        $Artists = @()

    static [void] RegisterWork([PublishedWork]$Work) {
        $wName   = $Work.Name
        $wArtist = $Work.Artist
        if ($Work -notin [PublishedWork]::List) {
            Write-Verbose "Adding work '$wName' to works list"
            [PublishedWork]::List += $Work
        } else {
            Write-Verbose "Work '$wName' already registered."
        }
        if ($wArtist -notin [PublishedWork]::Artists) {
            Write-Verbose "Adding artist '$wArtist' to artists list"
            [PublishedWork]::Artists += $wArtist
        } else {
            Write-Verbose "Artist '$wArtist' already registered."
        }
    }

    static [void] ClearRegistry() {
        Write-Verbose "Clearing PublishedWork registry"
        [PublishedWork]::List    = @()
        [PublishedWork]::Artists = @()
    }

    [string] $Name
    [string] $Artist
    [string] $Category

    [void] Init([string]$WorkType) {
        if ([string]::IsNullOrEmpty($this.Category)) {
            $this.Category = "${WorkType}s"
        }
    }

    PublishedWork() {
        $WorkType = $this.GetType().FullName
        $this.Init($WorkType)
        Write-Verbose "Defined a published work of type [$WorkType]"
    }

    PublishedWork([string]$Name, [string]$Artist) {
        $WorkType    = $this.GetType().FullName
        $this.Name   = $Name
        $this.Artist = $Artist
        $this.Init($WorkType)

        Write-Verbose "Defined '$Name' by $Artist as a published work of type [$WorkType]"
    }

    PublishedWork([string]$Name, [string]$Artist, [string]$Category) {
        $WorkType    = $this.GetType().FullName
        $this.Name   = $Name
        $this.Artist = $Artist
        $this.Init($WorkType)

        Write-Verbose "Defined '$Name' by $Artist ($Category) as a published work of type [$WorkType]"
    }

    [void]   Register() { [PublishedWork]::RegisterWork($this) }
    [string] ToString() { return "$($this.Name) by $($this.Artist)" }
}

Menentukan kelas turunan tanpa penimpaan

Kelas turunan pertama adalah Album. Ini tidak mengambil alih properti atau metode apa pun. Ini menambahkan properti instans baru, Genre, yang tidak ada di kelas dasar.

class Album : PublishedWork {
    [string[]] $Genres   = @()
}

Blok kode berikut menunjukkan perilaku kelas Album turunan. Pertama, ini mengatur $VerbosePreference sehingga pesan dari metode kelas memancarkan ke konsol. Ini membuat tiga instans kelas, menunjukkannya dalam tabel, lalu mendaftarkannya dengan metode statis RegisterWork() yang diwariskan. Kemudian memanggil metode statis yang sama pada kelas dasar secara langsung.

$VerbosePreference = 'Continue'
$Albums = @(
    [Album]@{
        Name   = 'The Dark Side of the Moon'
        Artist = 'Pink Floyd'
        Genres = 'Progressive rock', 'Psychedelic rock'
    }
    [Album]@{
        Name   = 'The Wall'
        Artist = 'Pink Floyd'
        Genres = 'Progressive rock', 'Art rock'
    }
    [Album]@{
        Name   = '36 Chambers'
        Artist = 'Wu-Tang Clan'
        Genres = 'Hip hop'
    }
)

$Albums | Format-Table
$Albums | ForEach-Object { [Album]::RegisterWork($_) }
$Albums | ForEach-Object { [PublishedWork]::RegisterWork($_) }
VERBOSE: Defined a published work of type [Album]
VERBOSE: Defined a published work of type [Album]
VERBOSE: Defined a published work of type [Album]

Genres                               Name                      Artist       Category
------                               ----                      ------       --------
{Progressive rock, Psychedelic rock} The Dark Side of the Moon Pink Floyd   Albums
{Progressive rock, Art rock}         The Wall                  Pink Floyd   Albums
{Hip hop}                            36 Chambers               Wu-Tang Clan Albums

VERBOSE: Adding work 'The Dark Side of the Moon' to works list
VERBOSE: Adding artist 'Pink Floyd' to artists list
VERBOSE: Adding work 'The Wall' to works list
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Adding work '36 Chambers' to works list
VERBOSE: Adding artist 'Wu-Tang Clan' to artists list

VERBOSE: Work 'The Dark Side of the Moon' already registered.
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Work 'The Wall' already registered.
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Work '36 Chambers' already registered.
VERBOSE: Artist 'Wu-Tang Clan' already registered.

Perhatikan bahwa meskipun kelas Album tidak menentukan nilai untuk Kategori atau konstruktor apa pun, properti ditentukan oleh konstruktor default kelas dasar.

Dalam olahpesan verbose, panggilan kedua ke RegisterWork() metode melaporkan bahwa karya dan seniman sudah terdaftar. Meskipun panggilan RegisterWork() pertama untuk adalah untuk kelas Album turunan, itu menggunakan metode statis yang diwariskan dari kelas PublishedWork dasar. Metode itu memperbarui properti Daftar statis dan Artis pada kelas dasar, yang tidak diambil alih oleh kelas turunan.

Blok kode berikutnya menghapus registri dan memanggil metode instans Register() pada objek Album .

[PublishedWork]::ClearRegistry()
$Albums.Register()
VERBOSE: Clearing PublishedWork registry

VERBOSE: Adding work 'The Dark Side of the Moon' to works list
VERBOSE: Adding artist 'Pink Floyd' to artists list
VERBOSE: Adding work 'The Wall' to works list
VERBOSE: Artist 'Pink Floyd' already registered.
VERBOSE: Adding work '36 Chambers' to works list
VERBOSE: Adding artist 'Wu-Tang Clan' to artists list

Metode instans pada objek Album memiliki efek yang sama dengan memanggil metode statis pada kelas turunan atau dasar.

Blok kode berikut membandingkan properti statis untuk kelas dasar dan kelas turunan, yang menunjukkan bahwa mereka sama.

[pscustomobject]@{
    '[PublishedWork]::List'    = [PublishedWork]::List -join ",`n"
    '[Album]::List'            = [Album]::List -join ",`n"
    '[PublishedWork]::Artists' = [PublishedWork]::Artists -join ",`n"
    '[Album]::Artists'         = [Album]::Artists -join ",`n"
    'IsSame::List'             = (
        [PublishedWork]::List.Count -eq [Album]::List.Count -and
        [PublishedWork]::List.ToString() -eq [Album]::List.ToString()
    )
    'IsSame::Artists'          = (
        [PublishedWork]::Artists.Count -eq [Album]::Artists.Count -and
        [PublishedWork]::Artists.ToString() -eq [Album]::Artists.ToString()
    )
} | Format-List
[PublishedWork]::List    : The Dark Side of the Moon by Pink Floyd,
                           The Wall by Pink Floyd,
                           36 Chambers by Wu-Tang Clan
[Album]::List            : The Dark Side of the Moon by Pink Floyd,
                           The Wall by Pink Floyd,
                           36 Chambers by Wu-Tang Clan
[PublishedWork]::Artists : Pink Floyd,
                           Wu-Tang Clan
[Album]::Artists         : Pink Floyd,
                           Wu-Tang Clan
IsSame::List             : True
IsSame::Artists          : True

Menentukan kelas turunan dengan penimpaan

Blok kode berikutnya mendefinisikan kelas Ilustrasi yang diwarisi dari kelas PublishedWork dasar. Kelas baru memperluas kelas dasar dengan mendefinisikan properti instans Medium dengan nilai Unknowndefault .

Tidak seperti kelas Album turunan, Ilustrasi mengambil alih properti dan metode berikut:

  • Ini mengambil alih properti Artis statis. Definisinya sama, tetapi kelas Ilustrasi mendeklarasikannya secara langsung.
  • Ini mengambil alih properti instans Kategori , mengatur nilai default ke Illustrations.
  • Ini mengambil alih ToString() metode instans sehingga representasi string dari ilustrasi mencakup media yang dibuat dengannya.

Kelas ini juga mendefinisikan metode statis RegisterIllustration() untuk terlebih dahulu memanggil metode kelas RegisterWork() dasar dan kemudian menambahkan artis ke properti statis Artis yang ditimpa pada kelas turunan.

Akhirnya, kelas mengambil alih ketiga konstruktor:

  1. Konstruktor default kosong kecuali untuk pesan verbose yang menunjukkan bahwa konstruktor membuat ilustrasi.
  2. Konstruktor berikutnya mengambil dua nilai string untuk nama dan artis yang membuat ilustrasi. Alih-alih menerapkan logika untuk mengatur properti Nama dan Artis , konstruktor memanggil konstruktor yang sesuai dari kelas dasar.
  3. Konstruktor terakhir mengambil tiga nilai string untuk nama, artis, dan medium ilustrasi. Kedua konstruktor menulis pesan verbose yang menunjukkan bahwa mereka membuat ilustrasi.
class Illustration : PublishedWork {
    static [string[]] $Artists = @()

    static [void] RegisterIllustration([Illustration]$Work) {
        $wArtist = $Work.Artist

        [PublishedWork]::RegisterWork($Work)

        if ($wArtist -notin [Illustration]::Artists) {
            Write-Verbose "Adding illustrator '$wArtist' to artists list"
            [Illustration]::Artists += $wArtist
        } else {
            Write-Verbose "Illustrator '$wArtist' already registered."
        }
    }

    [string] $Category = 'Illustrations'
    [string] $Medium   = 'Unknown'

    [string] ToString() {
        return "$($this.Name) by $($this.Artist) ($($this.Medium))"
    }

    Illustration() {
        Write-Verbose 'Defined an illustration'
    }

    Illustration([string]$Name, [string]$Artist) : base($Name, $Artist) {
        Write-Verbose "Defined '$Name' by $Artist ($($this.Medium)) as an illustration"
    }

    Illustration([string]$Name, [string]$Artist, [string]$Medium) {
        $this.Name = $Name
        $this.Artist = $Artist
        $this.Medium = $Medium

        Write-Verbose "Defined '$Name' by $Artist ($Medium) as an illustration"
    }
}

Blok kode berikut menunjukkan perilaku kelas Ilustrasi turunan. Ini membuat tiga instans kelas, menunjukkannya dalam tabel, lalu mendaftarkannya dengan metode statis RegisterWork() yang diwariskan. Kemudian memanggil metode statis yang sama pada kelas dasar secara langsung. Terakhir, ia menulis pesan yang menunjukkan daftar artis terdaftar untuk kelas dasar dan kelas turunan.

$Illustrations = @(
    [Illustration]@{
        Name   = 'The Funny Thing'
        Artist = 'Wanda Gág'
        Medium = 'Lithography'
    }
    [Illustration]::new('Millions of Cats', 'Wanda Gág')
    [Illustration]::new(
      'The Lion and the Mouse',
      'Jerry Pinkney',
      'Watercolor'
    )
)

$Illustrations | Format-Table
$Illustrations | ForEach-Object { [Illustration]::RegisterIllustration($_) }
$Illustrations | ForEach-Object { [PublishedWork]::RegisterWork($_) }
"Published work artists: $([PublishedWork]::Artists -join ', ')"
"Illustration artists: $([Illustration]::Artists -join ', ')"
VERBOSE: Defined a published work of type [Illustration]
VERBOSE: Defined an illustration
VERBOSE: Defined 'Millions of Cats' by Wanda Gág as a published work of type [Illustration]
VERBOSE: Defined 'Millions of Cats' by Wanda Gág (Unknown) as an illustration
VERBOSE: Defined a published work of type [Illustration]
VERBOSE: Defined 'The Lion and the Mouse' by Jerry Pinkney (Watercolor) as an illustration

Category      Medium      Name                   Artist
--------      ------      ----                   ------
Illustrations Lithography The Funny Thing        Wanda Gág
Illustrations Unknown     Millions of Cats       Wanda Gág
Illustrations Watercolor  The Lion and the Mouse Jerry Pinkney

VERBOSE: Adding work 'The Funny Thing' to works list
VERBOSE: Adding artist 'Wanda Gág' to artists list
VERBOSE: Adding illustrator 'Wanda Gág' to artists list
VERBOSE: Adding work 'Millions of Cats' to works list
VERBOSE: Artist 'Wanda Gág' already registered.
VERBOSE: Illustrator 'Wanda Gág' already registered.
VERBOSE: Adding work 'The Lion and the Mouse' to works list
VERBOSE: Adding artist 'Jerry Pinkney' to artists list
VERBOSE: Adding illustrator 'Jerry Pinkney' to artists list

VERBOSE: Work 'The Funny Thing' already registered.
VERBOSE: Artist 'Wanda Gág' already registered.
VERBOSE: Work 'Millions of Cats' already registered.
VERBOSE: Artist 'Wanda Gág' already registered.
VERBOSE: Work 'The Lion and the Mouse' already registered.
VERBOSE: Artist 'Jerry Pinkney' already registered.

Published work artists: Pink Floyd, Wu-Tang Clan, Wanda Gág, Jerry Pinkney

Illustration artists: Wanda Gág, Jerry Pinkney

Olahpesan verbose dari membuat instans menunjukkan bahwa:

  • Saat membuat instans pertama, konstruktor default kelas dasar dipanggil sebelum konstruktor default kelas turunan.
  • Saat membuat instans kedua, konstruktor yang diwariskan secara eksplisit dipanggil untuk kelas dasar sebelum konstruktor kelas turunan.
  • Saat membuat instans ketiga, konstruktor default kelas dasar dipanggil sebelum konstruktor kelas turunan.

Pesan verbose dari RegisterWork() metode menunjukkan bahwa karya dan seniman sudah terdaftar. Ini karena metode yang RegisterIllustration()RegisterWork() disebut metode secara internal.

Namun, ketika membandingkan nilai properti Artis statis untuk kelas dasar dan kelas turunan, nilainya berbeda. Properti Artis untuk kelas turunan hanya mencakup ilustrator, bukan artis album. Mendefinisikan ulang properti Artis di kelas turunan mencegah kelas mengembalikan properti statis pada kelas dasar.

Blok kode akhir memanggil ToString() metode pada entri properti Daftar statis pada kelas dasar.

[PublishedWork]::List | ForEach-Object -Process { $_.ToString() }
The Dark Side of the Moon by Pink Floyd
The Wall by Pink Floyd
36 Chambers by Wu-Tang Clan
The Funny Thing by Wanda Gág (Lithography)
Millions of Cats by Wanda Gág (Unknown)
The Lion and the Mouse by Jerry Pinkney (Watercolor)

Instans Album hanya mengembalikan nama dan artis dalam string mereka. Instans Ilustrasi juga menyertakan media dalam tanda kurung, karena kelas tersebut mengesampingkan ToString() metode .

Contoh 2 - Menerapkan antarmuka

Contoh berikut menunjukkan bagaimana kelas dapat menerapkan satu atau beberapa antarmuka. Contoh memperluas definisi kelas Suhu untuk mendukung lebih banyak operasi dan perilaku.

Definisi kelas awal

Sebelum menerapkan antarmuka apa pun, kelas Suhu didefinisikan dengan dua properti, Derajat dan Skala. Ini mendefinisikan konstruktor dan tiga metode instans untuk mengembalikan instans sebagai derajat skala tertentu.

Kelas menentukan skala yang tersedia dengan enumerasi TemperatureScale .

class Temperature {
    [float]            $Degrees
    [TemperatureScale] $Scale

    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale   = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius    { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5/9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5/9 }
            Kelvin     { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius    { return $this.Degrees * 9/5 + 32 }
            Kelvin     { return $this.Degrees * 9/5 - 459.67 }
        }
        return $this.Degrees
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

Namun, dalam implementasi dasar ini, ada beberapa batasan seperti yang ditunjukkan dalam contoh output berikut:

$Celsius    = [Temperature]::new()
$Fahrenheit = [Temperature]::new([TemperatureScale]::Fahrenheit)
$Kelvin     = [Temperature]::new(0, 'Kelvin')

$Celsius, $Fahrenheit, $Kelvin

"The temperatures are: $Celsius, $Fahrenheit, $Kelvin"

[Temperature]::new() -eq $Celsius

$Celsius -gt $Kelvin
Degrees      Scale
-------      -----
   0.00    Celsius
   0.00 Fahrenheit
   0.00     Kelvin

The temperatures are: Temperature, Temperature, Temperature

False

InvalidOperation:
Line |
  11 |  $Celsius -gt $Kelvin
     |  ~~~~~~~~~~~~~~~~~~~~
     | Cannot compare "Temperature" because it is not IComparable.

Output menunjukkan bahwa instans Suhu:

  • Jangan tampilkan dengan benar sebagai string.
  • Tidak dapat diperiksa dengan benar untuk kesetaraan.
  • Tidak dapat dibandingkan.

Ketiga masalah ini dapat diatasi dengan menerapkan antarmuka untuk kelas .

Menerapkan IFormattable

Antarmuka pertama yang diterapkan untuk kelas Suhu adalah System.IFormattable. Antarmuka ini memungkinkan pemformatan instans kelas sebagai string yang berbeda. Untuk mengimplementasikan antarmuka, kelas perlu mewarisi dari System.IFormattable dan menentukan ToString() metode instans.

Metode ToString() instans harus memiliki tanda tangan berikut:

[string] ToString(
    [string]$Format,
    [System.IFormatProvider]$FormatProvider
) {
    # Implementation
}

Tanda tangan yang diperlukan antarmuka tercantum dalam dokumentasi referensi.

Untuk Suhu, kelas harus mendukung tiga format: C untuk mengembalikan instans di Celcius, F untuk mengembalikannya di Fahrenheit, dan K mengembalikannya di Kelvin. Untuk format lain, metode harus melempar System.FormatException.

[string] ToString(
    [string]$Format,
    [System.IFormatProvider]$FormatProvider
) {
    # If format isn't specified, use the defined scale.
    if ([string]::IsNullOrEmpty($Format)) {
        $Format = switch ($this.Scale) {
            Celsius    { 'C' }
            Fahrenheit { 'F' }
            Kelvin     { 'K' }
        }
    }
    # If format provider isn't specified, use the current culture.
    if ($null -eq $FormatProvider) {
        $FormatProvider = [CultureInfo]::CurrentCulture
    }
    # Format the temperature.
    switch ($Format) {
        'C' {
            return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
        }
        'F' {
            return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
        }
        'K' {
            return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
        }
    }
    # If we get here, the format is invalid.
    throw [System.FormatException]::new(
        "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
    )
}

Dalam implementasi ini, metode default ke skala instans untuk format dan budaya saat ini saat memformat nilai derajat numerik itu sendiri. Ini menggunakan metode instans To<Scale>() untuk mengonversi derajat, memformatnya ke tempat dua desimal, dan menambahkan simbol derajat yang sesuai ke string.

Dengan tanda tangan yang diperlukan diimplementasikan, kelas juga dapat menentukan kelebihan beban untuk mempermudah pengembalian instans yang diformat.

[string] ToString([string]$Format) {
    return $this.ToString($Format, $null)
}

[string] ToString() {
    return $this.ToString($null, $null)
}

Kode berikut menunjukkan definisi yang diperbarui untuk Suhu:

class Temperature : System.IFormattable {
    [float]            $Degrees
    [TemperatureScale] $Scale

    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5 / 9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5 / 9 }
            Kelvin { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees * 9 / 5 + 32 }
            Kelvin { return $this.Degrees * 9 / 5 - 459.67 }
        }
        return $this.Degrees
    }

    [string] ToString(
        [string]$Format,
        [System.IFormatProvider]$FormatProvider
    ) {
        # If format isn't specified, use the defined scale.
        if ([string]::IsNullOrEmpty($Format)) {
            $Format = switch ($this.Scale) {
                Celsius    { 'C' }
                Fahrenheit { 'F' }
                Kelvin     { 'K' }
            }
        }
        # If format provider isn't specified, use the current culture.
        if ($null -eq $FormatProvider) {
            $FormatProvider = [CultureInfo]::CurrentCulture
        }
        # Format the temperature.
        switch ($Format) {
            'C' {
                return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
            }
            'F' {
                return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
            }
            'K' {
                return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
            }
        }
        # If we get here, the format is invalid.
        throw [System.FormatException]::new(
            "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
        )
    }

    [string] ToString([string]$Format) {
        return $this.ToString($Format, $null)
    }

    [string] ToString() {
        return $this.ToString($null, $null)
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

Output untuk metode kelebihan beban ditunjukkan di blok berikut.

$Temp = [Temperature]::new()
"The temperature is $Temp"
$Temp.ToString()
$Temp.ToString('K')
$Temp.ToString('F', $null)
The temperature is 0.00°C

0.00°C

273.15°K

32.00°F

Menerapkan IEquatable

Sekarang setelah kelas Suhu dapat diformat untuk keterbacaan, pengguna harus dapat memeriksa apakah dua instans kelas sama. Untuk mendukung pengujian ini, kelas perlu mengimplementasikan antarmuka System.IEquatable .

Untuk mengimplementasikan antarmuka, kelas perlu mewarisi dari System.IEquatable dan menentukan Equals() metode instans. Metode Equals() ini harus memiliki tanda tangan berikut:

[bool] Equals([object]$Other) {
    # Implementation
}

Tanda tangan yang diperlukan antarmuka tercantum dalam dokumentasi referensi.

Untuk Suhu, kelas hanya boleh mendukung perbandingan dua instans kelas. Untuk nilai atau jenis lainnya, termasuk $null, nilai harus mengembalikan $false. Ketika membandingkan dua suhu, metode harus mengonversi kedua nilai menjadi Kelvin, karena suhu dapat setara bahkan dengan skala yang berbeda.

[bool] Equals([object]$Other) {
    # If the other object is null, we can't compare it.
    if ($null -eq $Other) {
        return $false
    }

    # If the other object isn't a temperature, we can't compare it.
    $OtherTemperature = $Other -as [Temperature]
    if ($null -eq $OtherTemperature) {
        return $false
    }

    # Compare the temperatures as Kelvin.
    return $this.ToKelvin() -eq $OtherTemperature.ToKelvin()
}

Dengan metode antarmuka yang diterapkan, definisi yang diperbarui untuk Suhu adalah:

class Temperature : System.IFormattable, System.IEquatable[object] {
    [float]            $Degrees
    [TemperatureScale] $Scale

    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5 / 9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5 / 9 }
            Kelvin { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees * 9 / 5 + 32 }
            Kelvin { return $this.Degrees * 9 / 5 - 459.67 }
        }
        return $this.Degrees
    }

    [string] ToString(
        [string]$Format,
        [System.IFormatProvider]$FormatProvider
    ) {
        # If format isn't specified, use the defined scale.
        if ([string]::IsNullOrEmpty($Format)) {
            $Format = switch ($this.Scale) {
                Celsius    { 'C' }
                Fahrenheit { 'F' }
                Kelvin     { 'K' }
            }
        }
        # If format provider isn't specified, use the current culture.
        if ($null -eq $FormatProvider) {
            $FormatProvider = [CultureInfo]::CurrentCulture
        }
        # Format the temperature.
        switch ($Format) {
            'C' {
                return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
            }
            'F' {
                return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
            }
            'K' {
                return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
            }
        }
        # If we get here, the format is invalid.
        throw [System.FormatException]::new(
            "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
        )
    }

    [string] ToString([string]$Format) {
        return $this.ToString($Format, $null)
    }

    [string] ToString() {
        return $this.ToString($null, $null)
    }

    [bool] Equals([object]$Other) {
        # If the other object is null, we can't compare it.
        if ($null -eq $Other) {
            return $false
        }

        # If the other object isn't a temperature, we can't compare it.
        $OtherTemperature = $Other -as [Temperature]
        if ($null -eq $OtherTemperature) {
            return $false
        }

        # Compare the temperatures as Kelvin.
        return $this.ToKelvin() -eq $OtherTemperature.ToKelvin()
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

Blok berikut menunjukkan perilaku kelas yang diperbarui:

$Celsius    = [Temperature]::new()
$Fahrenheit = [Temperature]::new(32, 'Fahrenheit')
$Kelvin     = [Temperature]::new([TemperatureScale]::Kelvin)

@"
Temperatures are: $Celsius, $Fahrenheit, $Kelvin
`$Celsius.Equals(`$Fahrenheit) = $($Celsius.Equals($Fahrenheit))
`$Celsius -eq `$Fahrenheit     = $($Celsius -eq $Fahrenheit)
`$Celsius -ne `$Kelvin         = $($Celsius -ne $Kelvin)
"@
Temperatures are: 0.00°C, 32.00°F, 0.00°K

$Celsius.Equals($Fahrenheit) = True
$Celsius -eq $Fahrenheit     = True
$Celsius -ne $Kelvin         = True

Menerapkan IComparable

Antarmuka terakhir yang diterapkan untuk kelas Suhu adalah System.IComparable. Ketika kelas mengimplementasikan antarmuka ini, pengguna dapat menggunakan -ltoperator , , -le-gt, dan -ge untuk membandingkan instans kelas.

Untuk mengimplementasikan antarmuka, kelas perlu mewarisi dari System.IComparable dan menentukan Equals() metode instans. Metode Equals() ini harus memiliki tanda tangan berikut:

[int] CompareTo([Object]$Other) {
    # Implementation
}

Tanda tangan yang diperlukan antarmuka tercantum dalam dokumentasi referensi.

Untuk Suhu, kelas hanya boleh mendukung perbandingan dua instans kelas. Karena jenis yang mendasari properti Degrees, bahkan ketika dikonversi ke skala yang berbeda, adalah angka titik mengambang, metode dapat mengandalkan jenis yang mendasari untuk perbandingan aktual.

[int] CompareTo([object]$Other) {
    # If the other object's null, consider this instance "greater than" it
    if ($null -eq $Other) {
        return 1
    }
    # If the other object isn't a temperature, we can't compare it.
    $OtherTemperature = $Other -as [Temperature]
    if ($null -eq $OtherTemperature) {
        throw [System.ArgumentException]::new(
            "Object must be of type 'Temperature'."
        )
    }
    # Compare the temperatures as Kelvin.
    return $this.ToKelvin().CompareTo($OtherTemperature.ToKelvin())
}

Definisi akhir untuk kelas Suhu adalah:

class Temperature : System.IFormattable,
                    System.IComparable,
                    System.IEquatable[object] {
    # Instance properties
    [float]            $Degrees
    [TemperatureScale] $Scale

    # Constructors
    Temperature() {}
    Temperature([float] $Degrees)          { $this.Degrees = $Degrees }
    Temperature([TemperatureScale] $Scale) { $this.Scale = $Scale }
    Temperature([float] $Degrees, [TemperatureScale] $Scale) {
        $this.Degrees = $Degrees
        $this.Scale = $Scale
    }

    [float] ToKelvin() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees + 273.15 }
            Fahrenheit { return ($this.Degrees + 459.67) * 5 / 9 }
        }
        return $this.Degrees
    }
    [float] ToCelsius() {
        switch ($this.Scale) {
            Fahrenheit { return ($this.Degrees - 32) * 5 / 9 }
            Kelvin { return $this.Degrees - 273.15 }
        }
        return $this.Degrees
    }
    [float] ToFahrenheit() {
        switch ($this.Scale) {
            Celsius { return $this.Degrees * 9 / 5 + 32 }
            Kelvin { return $this.Degrees * 9 / 5 - 459.67 }
        }
        return $this.Degrees
    }

    [string] ToString(
        [string]$Format,
        [System.IFormatProvider]$FormatProvider
    ) {
        # If format isn't specified, use the defined scale.
        if ([string]::IsNullOrEmpty($Format)) {
            $Format = switch ($this.Scale) {
                Celsius    { 'C' }
                Fahrenheit { 'F' }
                Kelvin     { 'K' }
            }
        }
        # If format provider isn't specified, use the current culture.
        if ($null -eq $FormatProvider) {
            $FormatProvider = [CultureInfo]::CurrentCulture
        }
        # Format the temperature.
        switch ($Format) {
            'C' {
                return $this.ToCelsius().ToString('F2', $FormatProvider) + '°C'
            }
            'F' {
                return $this.ToFahrenheit().ToString('F2', $FormatProvider) + '°F'
            }
            'K' {
                return $this.ToKelvin().ToString('F2', $FormatProvider) + '°K'
            }
        }
        # If we get here, the format is invalid.
        throw [System.FormatException]::new(
            "Unknown format: '$Format'. Valid Formats are 'C', 'F', and 'K'"
        )
    }

    [string] ToString([string]$Format) {
        return $this.ToString($Format, $null)
    }

    [string] ToString() {
        return $this.ToString($null, $null)
    }

    [bool] Equals([object]$Other) {
        # If the other object is null, we can't compare it.
        if ($null -eq $Other) {
            return $false
        }
        # If the other object isn't a temperature, we can't compare it.
        $OtherTemperature = $Other -as [Temperature]
        if ($null -eq $OtherTemperature) {
            return $false
        }
        # Compare the temperatures as Kelvin.
        return $this.ToKelvin() -eq $OtherTemperature.ToKelvin()
    }
    [int] CompareTo([object]$Other) {
        # If the other object's null, consider this instance "greater than" it
        if ($null -eq $Other) {
            return 1
        }
        # If the other object isn't a temperature, we can't compare it.
        $OtherTemperature = $Other -as [Temperature]
        if ($null -eq $OtherTemperature) {
            throw [System.ArgumentException]::new(
                "Object must be of type 'Temperature'."
            )
        }
        # Compare the temperatures as Kelvin.
        return $this.ToKelvin().CompareTo($OtherTemperature.ToKelvin())
    }
}

enum TemperatureScale {
    Celsius    = 0
    Fahrenheit = 1
    Kelvin     = 2
}

Dengan definisi lengkap, pengguna dapat memformat dan membandingkan instans kelas di PowerShell seperti jenis bawaan apa pun.

$Celsius    = [Temperature]::new()
$Fahrenheit = [Temperature]::new(32, 'Fahrenheit')
$Kelvin     = [Temperature]::new([TemperatureScale]::Kelvin)

@"
Temperatures are: $Celsius, $Fahrenheit, $Kelvin
`$Celsius.Equals(`$Fahrenheit)    = $($Celsius.Equals($Fahrenheit))
`$Celsius.Equals(`$Kelvin)        = $($Celsius.Equals($Kelvin))
`$Celsius.CompareTo(`$Fahrenheit) = $($Celsius.CompareTo($Fahrenheit))
`$Celsius.CompareTo(`$Kelvin)     = $($Celsius.CompareTo($Kelvin))
`$Celsius -lt `$Fahrenheit        = $($Celsius -lt $Fahrenheit)
`$Celsius -le `$Fahrenheit        = $($Celsius -le $Fahrenheit)
`$Celsius -eq `$Fahrenheit        = $($Celsius -eq $Fahrenheit)
`$Celsius -gt `$Kelvin            = $($Celsius -gt $Kelvin)
"@
Temperatures are: 0.00°C, 32.00°F, 0.00°K
$Celsius.Equals($Fahrenheit)    = True
$Celsius.Equals($Kelvin)        = False
$Celsius.CompareTo($Fahrenheit) = 0
$Celsius.CompareTo($Kelvin)     = 1
$Celsius -lt $Fahrenheit        = False
$Celsius -le $Fahrenheit        = True
$Celsius -eq $Fahrenheit        = True
$Celsius -gt $Kelvin            = True

Contoh 3 - Mewarisi dari kelas dasar generik

Contoh ini menunjukkan bagaimana Anda dapat memperoleh dari kelas generik seperti System.Collections.Generic.List.

Menggunakan kelas bawaan sebagai parameter jenis

Jalankan blok kode berikut. Ini menunjukkan bagaimana kelas baru dapat mewarisi dari jenis generik selama parameter jenis sudah ditentukan pada waktu penguraian.

class ExampleStringList : System.Collections.Generic.List[string] {}

$List = [ExampleStringList]::New()
$List.AddRange([string[]]@('a','b','c'))
$List.GetType() | Format-List -Property Name, BaseType
$List
Name     : ExampleStringList
BaseType : System.Collections.Generic.List`1[System.String]

a
b
c

Menggunakan kelas kustom sebagai parameter jenis

Blok kode berikutnya pertama-tama mendefinisikan kelas baru, ExampleItem, dengan satu properti instans dan ToString() metode . Kemudian mendefinisikan kelas ExampleItemList yang mewarisi dari kelas dasar System.Collections.Generic.List dengan ExampleItem sebagai parameter jenis.

Salin seluruh blok kode dan jalankan sebagai satu pernyataan.

class ExampleItem {
    [string] $Name
    [string] ToString() { return $this.Name }
}
class ExampleItemList : System.Collections.Generic.List[ExampleItem] {}
ParentContainsErrorRecordException: An error occurred while creating the pipeline.

Menjalankan seluruh blok kode menimbulkan kesalahan karena PowerShell belum memuat kelas ExampleItem ke dalam runtime. Anda belum dapat menggunakan nama kelas sebagai parameter jenis untuk kelas dasar System.Collections.Generic.List .

Jalankan blok kode berikut dalam urutan yang ditentukan.

class ExampleItem {
    [string] $Name
    [string] ToString() { return $this.Name }
}
class ExampleItemList : System.Collections.Generic.List[ExampleItem] {}

Kali ini, PowerShell tidak menimbulkan kesalahan apa pun. Kedua kelas sekarang didefinisikan. Jalankan blok kode berikut untuk melihat perilaku kelas baru.

$List = [ExampleItemList]::New()
$List.AddRange([ExampleItem[]]@(
    [ExampleItem]@{ Name = 'Foo' }
    [ExampleItem]@{ Name = 'Bar' }
    [ExampleItem]@{ Name = 'Baz' }
))
$List.GetType() | Format-List -Property Name, BaseType
$List
Name     : ExampleItemList
BaseType : System.Collections.Generic.List`1[ExampleItem]

Name
----
Foo
Bar
Baz

Mengambil generik dengan parameter jenis kustom dalam modul

Blok kode berikut menunjukkan bagaimana Anda dapat menentukan kelas yang mewarisi dari kelas dasar generik yang menggunakan jenis kustom untuk parameter jenis.

Simpan blok kode berikut sebagai GenericExample.psd1.

@{
    RootModule        = 'GenericExample.psm1'
    ModuleVersion     = '0.1.0'
    GUID              = '2779fa60-0b3b-4236-b592-9060c0661ac2'
}

Simpan blok kode berikut sebagai GenericExample.InventoryItem.psm1.

class InventoryItem {
    [string] $Name
    [int]    $Count

    InventoryItem() {}
    InventoryItem([string]$Name) {
        $this.Name = $Name
    }
    InventoryItem([string]$Name, [int]$Count) {
        $this.Name  = $Name
        $this.Count = $Count
    }

    [string] ToString() {
        return "$($this.Name) ($($this.Count))"
    }
}

Simpan blok kode berikut sebagai GenericExample.psm1.

using namespace System.Collections.Generic
using module ./GenericExample.InventoryItem.psm1

class Inventory : List[InventoryItem] {}

# Define the types to export with type accelerators.
$ExportableTypes =@(
    [InventoryItem]
    [Inventory]
)
# 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()

Tip

Modul akar menambahkan jenis kustom ke akselerator jenis PowerShell. Pola ini memungkinkan pengguna modul untuk segera mengakses IntelliSense dan pelengkapan otomatis untuk jenis kustom tanpa perlu menggunakan pernyataan terlebih using module dahulu.

Untuk informasi selengkapnya tentang pola ini, lihat bagian "Mengekspor dengan akselerator jenis" di about_Classes.

Impor modul dan verifikasi output.

Import-Module ./GenericExample.psd1

$Inventory = [Inventory]::new()
$Inventory.GetType() | Format-List -Property Name, BaseType

$Inventory.Add([InventoryItem]::new('Bucket', 2))
$Inventory.Add([InventoryItem]::new('Mop'))
$Inventory.Add([InventoryItem]@{ Name = 'Broom' ; Count = 4 })
$Inventory
Name     : Inventory
BaseType : System.Collections.Generic.List`1[InventoryItem]

Name   Count
----   -----
Bucket     2
Mop        0
Broom      4

Modul dimuat tanpa kesalahan karena kelas InventoryItem didefinisikan dalam file modul yang berbeda dari kelas Inventori . Kedua kelas tersedia untuk pengguna modul.

Mewarisi kelas dasar

Ketika kelas mewarisi dari kelas dasar, kelas tersebut mewarisi properti dan metode kelas dasar. Ini tidak mewarisi konstruktor kelas dasar secara langsung, tetapi dapat memanggilnya.

Saat kelas dasar didefinisikan dalam .NET daripada PowerShell, perhatikan bahwa:

  • Kelas PowerShell tidak dapat mewarisi dari kelas yang disegel.
  • Saat mewarisi dari kelas dasar generik, parameter jenis untuk kelas generik tidak dapat menjadi kelas turunan. Menggunakan kelas turunan karena parameter jenis menimbulkan kesalahan penguraian.

Untuk melihat cara kerja pewarisan dan penimpaan untuk kelas turunan, lihat Contoh 1.

Konstruktor kelas turunan

Kelas turunan tidak secara langsung mewarisi konstruktor kelas dasar. Jika kelas dasar mendefinisikan konstruktor default dan kelas turunan tidak menentukan konstruktor apa pun, instans baru kelas turunan menggunakan konstruktor default kelas dasar. Jika kelas dasar tidak menentukan konstruktor default, kelas turunan harus secara eksplisit menentukan setidaknya satu konstruktor.

Konstruktor kelas turunan dapat memanggil konstruktor dari kelas dasar dengan base kata kunci. Jika kelas turunan tidak secara eksplisit memanggil konstruktor dari kelas dasar, itu memanggil konstruktor default untuk kelas dasar sebagai gantinya.

Untuk memanggil konstruktor dasar nondefault, tambahkan : base(<parameters>) setelah parameter konstruktor dan sebelum blok isi.

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

Saat menentukan konstruktor yang memanggil konstruktor kelas dasar, parameter dapat menjadi salah satu item berikut:

  • Variabel parameter apa pun pada konstruktor kelas turunan.
  • Nilai statis apa pun.
  • Ekspresi apa pun yang mengevaluasi ke nilai jenis parameter.

Kelas Ilustrasi di Contoh 1 menunjukkan bagaimana kelas turunan dapat menggunakan konstruktor kelas dasar.

Metode kelas turunan

Ketika kelas berasal dari kelas dasar, kelas tersebut mewarisi metode kelas dasar dan kelebihan bebannya. Setiap metode kelebihan beban yang ditentukan pada kelas dasar, termasuk metode tersembunyi, tersedia pada kelas turunan.

Kelas turunan dapat mengambil alih kelebihan metode yang diwariskan dengan mendefinisikannya kembali dalam definisi kelas. Untuk mengambil alih kelebihan beban, jenis parameter harus sama dengan untuk kelas dasar. Jenis output untuk kelebihan beban bisa berbeda.

Tidak seperti konstruktor, metode tidak dapat menggunakan : base(<parameters>) sintaks untuk memanggil kelebihan kelas dasar untuk metode . Kelebihan beban yang ditentukan ulang pada kelas turunan sepenuhnya menggantikan kelebihan beban yang ditentukan oleh kelas dasar. Untuk memanggil metode kelas dasar untuk instans, transmisikan variabel instans ($this) ke kelas dasar sebelum memanggil metode .

Cuplikan berikut menunjukkan bagaimana kelas turunan dapat memanggil metode kelas dasar.

class BaseClass {
    [bool] IsTrue() { return $true }
}
class DerivedClass : BaseClass {
    [bool] IsTrue()     { return $false }
    [bool] BaseIsTrue() { return ([BaseClass]$this).IsTrue() }
}

@"
[BaseClass]::new().IsTrue()        = $([BaseClass]::new().IsTrue())
[DerivedClass]::new().IsTrue()     = $([DerivedClass]::new().IsTrue())
[DerivedClass]::new().BaseIsTrue() = $([DerivedClass]::new().BaseIsTrue())
"@
[BaseClass]::new().IsTrue()        = True
[DerivedClass]::new().IsTrue()     = False
[DerivedClass]::new().BaseIsTrue() = True

Untuk sampel yang diperluas yang menunjukkan bagaimana kelas turunan dapat mengambil alih metode yang diwariskan, lihat kelas Ilustrasi di Contoh 1.

Properti kelas turunan

Ketika kelas berasal dari kelas dasar, kelas tersebut mewarisi properti kelas dasar. Properti apa pun yang ditentukan pada kelas dasar, termasuk properti tersembunyi, tersedia di kelas turunan.

Kelas turunan dapat mengambil alih properti yang diwariskan dengan mendefinisikannya kembali dalam definisi kelas. Properti pada kelas turunan menggunakan jenis yang ditentukan ulang dan nilai default, jika ada. Jika properti yang diwariskan menentukan nilai default dan properti yang ditentukan ulang tidak, properti yang diwariskan tidak memiliki nilai default.

Jika kelas turunan tidak mengambil alih properti statis, mengakses properti statis melalui kelas turunan mengakses properti statis kelas dasar. Memodifikasi nilai properti melalui kelas turunan memodifikasi nilai pada kelas dasar. Kelas turunan lainnya yang tidak mengambil alih properti statis juga menggunakan nilai properti pada kelas dasar. Memperbarui nilai properti statis yang diwariskan di kelas yang tidak mengambil alih properti mungkin memiliki efek yang tidak diinginkan untuk kelas yang berasal dari kelas dasar yang sama.

Contoh 1 menunjukkan bagaimana kelas turunan yang mewarisi, memperluas, dan mengambil alih properti kelas dasar.

Berasal dari generik

Ketika kelas berasal dari generik, parameter jenis harus sudah ditentukan sebelum PowerShell mengurai kelas turunan. Jika parameter jenis untuk generik adalah kelas PowerShell atau enumerasi yang ditentukan dalam file atau blok kode yang sama, PowerShell menimbulkan kesalahan.

Untuk mendapatkan kelas dari kelas dasar generik dengan jenis kustom sebagai parameter jenis, tentukan kelas atau enumerasi untuk parameter jenis dalam file atau modul yang berbeda dan gunakan using module pernyataan untuk memuat definisi jenis.

Untuk contoh yang menunjukkan cara mewarisi dari kelas dasar generik, lihat Contoh 3.

Kelas yang berguna untuk diwarisi

Ada beberapa kelas yang dapat berguna untuk diwarisi saat menulis modul PowerShell. Bagian ini mencantumkan beberapa kelas dasar dan kelas yang berasal dari kelas tersebut dapat digunakan.

  • System.Attribute - Mendapatkan kelas untuk menentukan atribut yang dapat digunakan untuk variabel, parameter, definisi kelas dan enumerasi, dan banyak lagi.
  • System.Management.Automation.ArgumentTransformationAttribute - Kelas turunan untuk menangani konversi input untuk variabel atau parameter ke dalam jenis data tertentu.
  • System.Management.Automation.ValidateArgumentsAttribute - Turunkan kelas untuk menerapkan validasi kustom ke variabel, parameter, dan properti kelas.
  • System.Collections.Generic.List - Mendapatkan kelas untuk membuat dan mengelola daftar jenis data tertentu lebih mudah.
  • System.Exception - Memperoleh kelas untuk menentukan kesalahan kustom.

Menerapkan antarmuka

Kelas PowerShell yang mengimplementasikan antarmuka harus mengimplementasikan semua anggota antarmuka tersebut. Menghilangkan anggota antarmuka implementasi menyebabkan kesalahan penguraian waktu dalam skrip.

Catatan

PowerShell tidak mendukung deklarasikan antarmuka baru dalam skrip PowerShell. Sebagai gantinya, antarmuka harus dideklarasikan dalam kode .NET dan ditambahkan ke sesi dengan Add-Type cmdlet atau using assembly pernyataan .

Ketika kelas mengimplementasikan antarmuka, itu dapat digunakan seperti kelas lain yang mengimplementasikan antarmuka tersebut. Beberapa perintah dan operasi membatasi jenis yang didukung ke kelas yang mengimplementasikan antarmuka tertentu.

Untuk meninjau implementasi sampel antarmuka, lihat Contoh 2.

Antarmuka yang berguna untuk diimplementasikan

Ada beberapa kelas antarmuka yang dapat berguna untuk mewarisi saat menulis modul PowerShell. Bagian ini mencantumkan beberapa kelas dasar dan kelas yang berasal dari kelas tersebut dapat digunakan.

  • System.IEquatable - Antarmuka ini memungkinkan pengguna untuk membandingkan dua instans kelas. Saat kelas tidak menerapkan antarmuka ini, PowerShell memeriksa kesetaraan antara dua instans menggunakan kesetaraan referensi. Dengan kata lain, instans kelas hanya sama dengan dirinya sendiri, bahkan jika nilai properti pada dua instans sama.
  • System.IComparable - Antarmuka ini memungkinkan pengguna untuk membandingkan instans kelas dengan -leoperator perbandingan , -lt, -ge, dan -gt . Ketika kelas tidak menerapkan antarmuka ini, operator tersebut menimbulkan kesalahan.
  • System.IFormattable - Antarmuka ini memungkinkan pengguna memformat instans kelas ke dalam string yang berbeda. Ini berguna untuk kelas yang memiliki lebih dari satu representasi string standar, seperti item anggaran, bibliografi, dan suhu.
  • System.IConvertible - Antarmuka ini memungkinkan pengguna untuk mengonversi instans kelas ke jenis runtime lainnya. Ini berguna untuk kelas yang memiliki nilai numerik yang mendasar atau dapat dikonversi menjadi satu.

Batasan

  • PowerShell tidak mendukung pendefinisian antarmuka dalam kode skrip.

    Solusi sementara: Tentukan antarmuka di C# dan referensikan rakitan yang menentukan antarmuka.

  • Kelas PowerShell hanya dapat mewarisi dari satu kelas dasar.

    Solusi sementara: Pewarisan kelas bersifat transitif. Kelas turunan dapat mewarisi dari kelas turunan lain untuk mendapatkan properti dan metode kelas dasar.

  • Saat mewarisi dari kelas atau antarmuka generik, parameter jenis untuk generik harus sudah ditentukan. Kelas tidak dapat mendefinisikan dirinya sebagai parameter jenis untuk kelas atau antarmuka.

    Solusi sementara: Untuk memperoleh dari kelas atau antarmuka dasar generik, tentukan jenis kustom dalam file yang berbeda .psm1 dan gunakan using module pernyataan untuk memuat jenis. Tidak ada solusi untuk jenis kustom untuk menggunakan dirinya sendiri sebagai parameter jenis saat mewarisi dari generik.

Lihat Juga