Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Breve descrizione
Viene descritto come definire classi che estendono altri tipi.
Descrizione lunga
Le classi di PowerShell supportano ereditarietà, che consente di definire una classe figlia che riutilizza (eredita), estende o modifica il comportamento di una classe padre. La classe i cui membri vengono ereditati viene chiamata classe base . La classe che eredita i membri della classe base viene chiamata classe derivata .
PowerShell supporta solo l'ereditarietà singola. Una classe può ereditare solo da una singola classe. Tuttavia, l'ereditarietà è transitiva, che consente di definire una gerarchia di ereditarietà per un set di tipi. In altre parole, il tipo D può ereditare dal tipo C, che eredita dal tipo B, che eredita dal tipo di classe base A. Poiché l'ereditarietà è transitiva, i membri del tipo A sono disponibili per il tipo D.
Le classi derivate non ereditano tutti i membri della classe base. I membri seguenti non vengono ereditati:
- Costruttori statici, che inizializzano i dati statici di una classe.
- Costruttori di istanza, chiamati per creare una nuova istanza della classe . Ogni classe deve definire i propri costruttori.
È possibile estendere una classe creando una nuova classe che deriva da una classe esistente. La classe derivata eredita le proprietà e i metodi della classe base. È possibile aggiungere o eseguire l'override dei membri della classe base in base alle esigenze.
Le classi possono anche ereditare da interfacce, che definiscono un contratto. Una classe che eredita da un'interfaccia deve implementare tale contratto. Quando lo fa, la classe è utilizzabile come qualsiasi altra classe che implementa tale interfaccia. Se una classe eredita da un'interfaccia ma non implementa l'interfaccia, PowerShell genera un errore di analisi per la classe .
Alcuni operatori di PowerShell dipendono da una classe che implementa un'interfaccia specifica.
Ad esempio, l'operatore -le, -lt, -gee -gt funzionano solo su classi che implementano l'interfaccia System.IComparable.
Una classe derivata usa la sintassi : per estendere una classe base o implementare interfacce. La classe derivata deve essere sempre all'estrema sinistra nella dichiarazione di classe.
In questo esempio viene illustrata la sintassi di ereditarietà della classe PowerShell di base.
class Derived : Base {...}
Questo esempio mostra l'ereditarietà con una dichiarazione di interfaccia successiva alla classe base.
class Derived : Base, Interface {...}
Sintassi
L'ereditarietà della classe usa le sintassi seguenti:
Sintassi di una riga
class <derived-class-name> : <base-class-or-interface-name>[, <interface-name>...] {
<derived-class-body>
}
Per esempio:
# Base class only
class Derived : Base {...}
# Interface only
class Derived : System.IComparable {...}
# Base class and interface
class Derived : Base, System.IComparable {...}
Sintassi multilinea
class <derived-class-name> : <base-class-or-interface-name>[,
<interface-name>...] {
<derived-class-body>
}
Per esempio:
class Derived : Base,
System.IComparable,
System.IFormattable,
System.IConvertible {
# Derived class definition
}
Esempi
Esempio 1 - Ereditarietà e override di una classe base
Nell'esempio seguente viene illustrato il comportamento delle proprietà ereditate con e senza eseguire l'override. Eseguire i blocchi di codice in ordine dopo aver letto la descrizione.
Definizione della classe base
Il primo blocco di codice definisce PublishedWork come classe base. Dispone di due proprietà statiche: List e Artists. Successivamente, definisce il metodo RegisterWork() statico per aggiungere opere alla proprietà statica List e gli artisti alla proprietà Artists, scrivendo un messaggio per ogni nuova voce negli elenchi.
La classe definisce tre proprietà di istanza che descrivono un lavoro pubblicato.
Definisce infine i metodi di istanza di Register() e 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)" }
}
Definizione di una classe derivata senza override
La prima classe derivata è Album. Non esegue l'override di alcuna proprietà o metodo. Aggiunge una nuova proprietà dell'istanza, Genres, che non esiste nella classe base.
class Album : PublishedWork {
[string[]] $Genres = @()
}
Il blocco di codice seguente mostra il comportamento della classe Album derivata.
Prima di tutto, imposta il $VerbosePreference in modo che i messaggi dei metodi della classe vengano inviati alla console. Crea tre istanze della classe, le mostra in una tabella e quindi le registra con il metodo statico RegisterWork() ereditato. Chiama quindi direttamente lo stesso metodo statico sulla classe base.
$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.
Si noti che anche se la classe album
Nella messaggistica verbosa, la seconda chiamata al metodo RegisterWork() riporta che le opere e gli artisti sono già registrati. Anche se la prima chiamata a RegisterWork() era per la classe derivata Album , utilizzava il metodo statico ereditato dalla classe base PublishedWork. Questo metodo ha aggiornato le proprietà statiche List e Artist nella classe base, su cui la classe derivata non ha eseguito l'override.
Il blocco di codice successivo cancella il registro e chiama il metodo di istanza
[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
Il metodo di istanza negli oggetti album
Il blocco di codice seguente confronta le proprietà statiche per la classe di base e la classe derivata, mostrando che sono uguali.
[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
Definizione di una classe derivata con sovrascritture
Il blocco di codice successivo definisce la classe Illustration che eredita dalla classe di base PublishedWork. La nuova classe estende la classe base definendo la proprietà dell'istanza Medium con un valore predefinito di Unknown.
A differenza della classe Album
- Esegue l'override della proprietà statica Artists. La definizione è la stessa, ma la classe Illustrazione la dichiara direttamente.
- Esegue l'override della proprietà di istanza della categoria , impostando il valore predefinito a
Illustrations. - Esegue l'override del metodo di istanza
ToString()in modo che la rappresentazione di stringa di un'illustrazione includa il supporto con cui è stato creato.
La classe definisce anche il metodo statico RegisterIllustration() per chiamare prima il metodo RegisterWork() della classe base e quindi aggiungere l'artista alla proprietà statica ridefinita Artists nella classe derivata.
Infine, la classe esegue l'override di tutti e tre i costruttori:
- Il costruttore predefinito è vuoto, ad eccezione di un messaggio dettagliato che indica che è stata creata un'illustrazione.
- Il costruttore successivo accetta due valori stringa per il nome e l'artista che ha creato l'illustrazione. Anziché implementare la logica per impostare le proprietà Name
e Artist , il costruttore chiama il costruttore appropriato dalla classe base. - L'ultimo costruttore accetta tre valori di stringa per il nome, l'artista e il medium dell'illustrazione. Entrambi i costruttori scrivono un messaggio dettagliato che indica che hanno creato un'illustrazione.
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"
}
}
Il blocco di codice seguente illustra il comportamento della classe Illustrazione RegisterWork() ereditato. Chiama quindi direttamente lo stesso metodo statico sulla classe base. Infine, scrive messaggi che mostrano l'elenco di artisti registrati per la classe base e la classe derivata.
$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
La messaggistica verbosa dall'operazione di creazione delle istanze mostra che:
- Quando si crea la prima istanza, il costruttore predefinito della classe base è stato chiamato prima del costruttore predefinito della classe derivata.
- Quando si crea la seconda istanza, il costruttore ereditato in modo esplicito è stato chiamato per la classe base prima del costruttore della classe derivata.
- Quando si crea la terza istanza, il costruttore predefinito della classe base è stato chiamato prima del costruttore della classe derivata.
I messaggi dettagliati del metodo RegisterWork() indicano che le opere e gli artisti sono già stati registrati. Questo è dovuto al fatto che il metodo RegisterIllustration() invoca internamente il metodo RegisterWork().
Tuttavia, quando si confronta il valore della proprietà static Artist sia per la classe di base che per la classe derivata, i valori sono diversi. La proprietà Artisti per la classe derivata include solo illustratori, non gli artisti dell'album. La ridefinizione della proprietà
Il blocco di codice finale chiama il metodo
[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)
Le istanze di Album restituiscono solo il nome e l'artista nella stringa. Le istanze di Illustrazione includevano anche il medium tra parentesi, perché tale classe sovrascriveva il metodo ToString().
Esempio 2 - Implementazione di interfacce
Nell'esempio seguente viene illustrato come una classe può implementare una o più interfacce. L'esempio estende la definizione di una classe di Temperature per supportare più operazioni e comportamenti.
Definizione della classe iniziale
Prima di implementare qualsiasi interfaccia, la classe Temperature viene definita con due proprietà, Gradi e Scala. Vengono definiti costruttori e tre metodi di istanza per restituire il valore dell'istanza come gradi di una determinata scala.
La classe definisce le scale disponibili con l'enumerazione 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
}
In questa implementazione di base, tuttavia, esistono alcune limitazioni, come illustrato nell'output di esempio seguente:
$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.
L'output mostra che le istanze di Temperature:
- Non vengono mostrate correttamente come stringhe.
- Non è possibile verificare correttamente l'equivalenza.
- Non è possibile confrontare.
Questi tre problemi possono essere risolti implementando interfacce per la classe .
Implementazione di IFormattable
La prima interfaccia da implementare per la classe Temperature è System.IFormattable. Questa interfaccia abilita la formattazione di un'istanza della classe come stringhe diverse. Per implementare l'interfaccia, la classe deve ereditare da System.IFormattable e definire il metodo di istanza ToString().
Il metodo di istanza di ToString() deve avere la firma seguente:
[string] ToString(
[string]$Format,
[System.IFormatProvider]$FormatProvider
) {
# Implementation
}
La firma richiesta dall'interfaccia è elencata nella documentazione di riferimento .
Per Temperature, la classe deve supportare tre formati: C per restituire l'istanza in Celsius, F per restituirla in Fahrenheit e K per restituirla in Kelvin. Per qualsiasi altro formato, il metodo deve generare un 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'"
)
}
In questa implementazione, per impostazione predefinita, il metodo utilizza la scala dell'istanza per il formato e la cultura corrente durante la formattazione del valore numerico del grado. Usa i metodi di istanza To<Scale>() per convertire i gradi, formattarli in posizioni decimali e accoda il simbolo di grado appropriato alla stringa.
Con la firma necessaria implementata, la classe può anche definire sovraccarichi per semplificare la restituzione dell'istanza formattata.
[string] ToString([string]$Format) {
return $this.ToString($Format, $null)
}
[string] ToString() {
return $this.ToString($null, $null)
}
Il codice seguente illustra la definizione aggiornata per Temperature:
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
}
L'output delle sovraccaricature del metodo è illustrato nel blocco seguente.
$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
Implementazione di IEquatable
Ora che la classe temperature
Per implementare l'interfaccia, la classe deve ereditare da System.IEquatable e definire il metodo di istanza Equals(). Il metodo Equals() deve avere la firma seguente:
[bool] Equals([Object]$Other) {
# Implementation
}
La firma richiesta dall'interfaccia è elencata nella documentazione di riferimento .
Per Temperature, la classe deve supportare solo il confronto di due istanze della classe . Per qualsiasi altro valore o tipo, incluso $null, deve restituire $false. Quando si confrontano due temperature, il metodo deve convertire entrambi i valori in Kelvin, poiché le temperature possono essere equivalenti anche con scale diverse.
[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()
}
Con il metodo di interfaccia implementato, la definizione aggiornata per Temperature è:
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
}
Il blocco seguente illustra il comportamento della classe aggiornata:
$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
Implementazione di IComparable
L'ultima interfaccia da implementare per la classe Temperature è System.IComparable. Quando la classe implementa questa interfaccia, gli utenti possono usare gli operatori -lt, -le, -gte -ge per confrontare le istanze della classe .
Per implementare l'interfaccia, la classe deve ereditare da System.IComparable e definire il metodo di istanza Equals(). Il metodo Equals() deve avere la firma seguente:
[int] CompareTo([Object]$Other) {
# Implementation
}
La firma richiesta dall'interfaccia è elencata nella documentazione di riferimento .
Per Temperature, la classe deve supportare solo il confronto di due istanze della classe . Poiché il tipo sottostante per la proprietà gradi, anche quando viene convertito in una scala diversa, è un numero a virgola mobile, il metodo può fare affidamento sul tipo sottostante per il confronto effettivo.
[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())
}
La definizione finale per la classe Temperatura è:
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
}
Con la definizione completa, gli utenti possono formattare e confrontare istanze della classe in PowerShell come qualsiasi tipo predefinito.
$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
Esempio 3 - Eredità da una classe base generica
In questo esempio viene illustrato come derivare da un tipo generico purché il parametro di tipo sia già definito in fase di analisi.
Uso di una classe predefinita come parametro di tipo
Eseguire il blocco di codice seguente. Mostra come una nuova classe può ereditare da un tipo generico purché il parametro di tipo sia già definito in fase di analisi.
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
Uso di una classe personalizzata come parametro di tipo
Il blocco di codice successivo definisce prima una nuova classe, ExampleItem, con una singola proprietà dell'istanza e il metodo ToString(). Definisce quindi la classe ExampleItemList che eredita dalla classe di base System.Collections.Generic.List con ExampleItem come parametro di tipo.
Copiare l'intero blocco di codice ed eseguirlo come singola istruzione.
class ExampleItem {
[string] $Name
[string] ToString() { return $this.Name }
}
class ExampleItemList : System.Collections.Generic.List[ExampleItem] {}
ParentContainsErrorRecordException: An error occurred while creating the pipeline.
L'esecuzione dell'intero blocco di codice genera un errore perché PowerShell non ha ancora caricato la classe ExampleItem
Eseguire i blocchi di codice seguenti nell'ordine in cui sono definiti.
class ExampleItem {
[string] $Name
[string] ToString() { return $this.Name }
}
class ExampleItemList : System.Collections.Generic.List[ExampleItem] {}
Questa volta, PowerShell non genera errori. Entrambe le classi sono ora definite. Eseguire il blocco di codice seguente per visualizzare il comportamento della nuova classe.
$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
Derivazione di un generico con un parametro di tipo personalizzato in un modulo
I blocchi di codice seguenti illustrano come definire una classe che eredita da una classe di base generica che usa un tipo personalizzato per il parametro di tipo.
Salvare il blocco di codice seguente come GenericExample.psd1.
@{
RootModule = 'GenericExample.psm1'
ModuleVersion = '0.1.0'
GUID = '2779fa60-0b3b-4236-b592-9060c0661ac2'
}
Salvare il blocco di codice seguente come 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))"
}
}
Salvare il blocco di codice seguente come 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()
Mancia
Il modulo radice aggiunge i tipi personalizzati agli acceleratori di tipi di PowerShell. Questo modello consente agli utenti del modulo di accedere immediatamente a IntelliSense e al completamento automatico per i tipi personalizzati senza dover usare prima l'istruzione using module.
Per altre informazioni su questo modello, vedere la sezione "Esportazione con acceleratori di tipi" di about_Classes.
Importare il modulo e verificare l'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
Il modulo viene caricato senza errori perché la classe InventoryItem
Ereditarietà di una classe base
Quando una classe eredita da una classe di base, eredita le proprietà e i metodi della classe base. Non eredita direttamente i costruttori della classe di base, ma può chiamarli.
Quando la classe base è definita in .NET anziché In PowerShell, tenere presente che:
- Le classi di PowerShell non possono ereditare da classi sigillate.
- Quando eredita da una classe di base generica, il parametro di tipo per la classe generica non può essere la classe derivata. L'uso della classe derivata come parametro di tipo genera un errore di analisi.
Per informazioni sul funzionamento dell'ereditarietà e dell'override per le classi derivate, vedere esempio 1.
Costruttori di classi derivate
Le classi derivate non ereditano direttamente i costruttori della classe base. Se la classe base definisce un costruttore predefinito e la classe derivata non definisce costruttori, le nuove istanze della classe derivata usano il costruttore predefinito della classe base. Se la classe base non definisce un costruttore predefinito, la classe derivata deve definire in modo esplicito almeno un costruttore.
I costruttori di classi derivate possono richiamare un costruttore dalla classe base con la parola chiave base. Se la classe derivata non richiama in modo esplicito un costruttore dalla classe base, richiama invece il costruttore predefinito per la classe base.
Per richiamare un costruttore di base non predefinito, aggiungere : base(<parameters>) dopo i parametri del costruttore e prima del blocco del corpo.
class <derived-class> : <base-class> {
<derived-class>(<derived-parameters>) : <base-class>(<base-parameters>) {
# initialization code
}
}
Quando si definisce un costruttore che chiama un costruttore di classe base, i parametri possono essere uno degli elementi seguenti:
- Variabile di qualsiasi parametro nel costruttore della classe derivata.
- Qualsiasi valore statico.
- Qualsiasi espressione che restituisce un valore del tipo di parametro.
La classe di Illustrazione in Esempio 1 mostra come una classe derivata può utilizzare i costruttori della classe base.
Metodi della classe derivata
Quando una classe deriva da una classe di base, eredita i metodi della classe di base e i relativi overload. Tutti gli overload di metodo definiti nella classe base, inclusi i metodi nascosti, sono disponibili nella classe derivata.
Una classe derivata può eseguire l'override di un overload di metodo ereditato ridefinendolo nella definizione della classe. Per eseguire l'override dell'overload, i tipi di parametro devono essere uguali a quello della classe base. Il tipo di output per l'overload può essere diverso.
A differenza dei costruttori, i metodi non possono usare la sintassi : base(<parameters>) per richiamare un overload della classe di base per il metodo . L'overload ridefinito nella classe derivata sostituisce completamente l'overload definito dalla classe base. Per chiamare il metodo della classe base per un'istanza, eseguire il cast della variabile di istanza ($this) alla classe base prima di chiamare il metodo.
Il frammento di codice seguente mostra come una classe derivata può chiamare il metodo della classe base.
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
Per un esempio esteso che illustra come una classe derivata può eseguire l'override dei metodi ereditati, vedere la classe Illustrazione
Proprietà della classe derivata
Quando una classe deriva da una classe di base, eredita le proprietà della classe base. Tutte le proprietà definite nella classe base, incluse le proprietà nascoste, sono disponibili nella classe derivata.
Una classe derivata può eseguire l'override di una proprietà ereditata definendola nella definizione della classe. La proprietà nella classe derivata utilizza il tipo ridefinito e il valore predefinito, se presenti. Se la proprietà ereditata ha definito un valore predefinito e la proprietà ridefinita non lo fa, la proprietà ereditata non ha alcun valore predefinito.
Se una classe derivata non esegue l'override di una proprietà statica, l'accesso alla proprietà statica tramite la classe derivata accede alla proprietà statica della classe base. La modifica del valore della proprietà tramite la classe derivata modifica il valore nella classe base. Qualsiasi altra classe derivata che non esegue l'override della proprietà statica usa anche il valore della proprietà nella classe di base. L'aggiornamento del valore di una proprietà statica ereditata in una classe che non esegue l'override della proprietà potrebbe avere effetti imprevisti per le classi derivate dalla stessa classe di base.
esempio 1 illustra come le classi derivate che ereditano, estendono ed eseguono l'override delle proprietà della classe di base.
Derivazione da generici
Quando una classe deriva da un oggetto generico, il parametro di tipo deve essere già definito prima che PowerShell analizzi la classe derivata. Se il parametro di tipo per il generico è una classe di PowerShell o un'enumerazione definita nello stesso file o blocco di codice, PowerShell genera un errore.
Per derivare una classe da una classe base generica con un tipo personalizzato come parametro di tipo, definire la classe o l'enumerazione per il parametro di tipo in un file o modulo diverso e usare l'istruzione using module per caricare la definizione del tipo.
Per un esempio che illustra come ereditare da una classe di base generica, vedere esempio 3.
Classi utili da ereditare
Esistono alcune classi che possono essere utili per ereditare durante la creazione di moduli di PowerShell. In questa sezione sono elencate alcune classi di base e le classi per cui è possibile usare una classe derivata.
- System.Attribute: derivare classi per definire attributi che possono essere usati per variabili, parametri, definizioni di classe ed enumerazione e altro ancora.
- System.Management.Automation.ArgumentTransformationAttribute - Derivare le classi per gestire la conversione dell'input per una variabile o un parametro in un tipo di dati specifico.
- System.Management.Automation.ValidateArgumentsAttribute - Derivare classi per applicare la convalida personalizzata a variabili, parametri e proprietà di classe.
- System.Collections.Generic.List - Derivare classi per semplificare la creazione e la gestione di elenchi di un tipo di dati specifico.
- System.Exception - Derivare classi per definire errori personalizzati.
Implementazione di interfacce
Una classe di PowerShell che implementa un'interfaccia deve implementare tutti i membri di tale interfaccia. L'omissione dei membri dell'interfaccia di implementazione causa un errore in fase di analisi nello script.
Nota
PowerShell non supporta la dichiarazione di nuove interfacce nello script di PowerShell.
Al contrario, le interfacce devono essere dichiarate nel codice .NET e aggiunte alla sessione con il cmdlet Add-Type o l'istruzione using assembly.
Quando una classe implementa un'interfaccia, può essere usata come qualsiasi altra classe che implementa tale interfaccia. Alcuni comandi e operazioni limitano i tipi supportati alle classi che implementano un'interfaccia specifica.
Per esaminare un'implementazione di esempio di interfacce, vedere esempio 2.
Interfacce utili da implementare
Esistono alcune classi di interfaccia che possono essere utili per ereditare durante la creazione di moduli di PowerShell. In questa sezione sono elencate alcune classi di base e le classi per cui è possibile usare una classe derivata.
- System.IEquatable: questa interfaccia consente agli utenti di confrontare due istanze della classe. Quando una classe non implementa questa interfaccia, PowerShell verifica la parità tra due istanze usando l'uguaglianza dei riferimenti. In altre parole, un'istanza della classe è uguale solo a se stessa, anche se i valori delle proprietà in due istanze sono uguali.
-
System.IComparable: questa interfaccia consente agli utenti di confrontare le istanze della classe con gli operatori di confronto
-le,-lt,-gee-gt. Quando una classe non implementa questa interfaccia, tali operatori generano un errore. - System.IFormattable: questa interfaccia consente agli utenti di formattare le istanze della classe in stringhe diverse. Ciò è utile per le classi con più di una rappresentazione di stringa standard, ad esempio articoli di budget, bibliografie e temperature.
- System.IConvertible: questa interfaccia consente agli utenti di convertire istanze della classe in altri tipi di runtime. Ciò è utile per le classi che hanno un valore numerico sottostante o possono essere convertite in una classe.
Limitazioni
PowerShell non supporta la definizione di interfacce nel codice script.
Soluzione alternativa: definire le interfacce in C# e fare riferimento all'assembly che definisce le interfacce.
Le classi di PowerShell possono ereditare solo da una classe di base.
Soluzione alternativa: l'ereditarietà della classe è transitiva. Una classe derivata può ereditare da un'altra classe derivata per ottenere le proprietà e i metodi di una classe base.
Quando eredita da una classe o un'interfaccia generica, il parametro di tipo per il generico deve essere già definito. Una classe non può definirsi come parametro di tipo per una classe o un'interfaccia.
Soluzione alternativa: per derivare da una classe o un'interfaccia di base generica, definire il tipo personalizzato in un file di
.psm1diverso e usare l'istruzioneusing moduleper caricare il tipo. Non c'è soluzione per un tipo personalizzato che usi sé stesso come parametro di tipo quando eredita da un generico.