PowerShell 面向对象

PowerShell 面向对象

PowerShell 是一种强大的脚本语言,主要用于基于 Windows 的系统管理自动化。它支持面向对象编程(OOP),允许开发者创建类、实例化对象以及使用继承等特性来构建复杂的程序结构。

PowerShell 从版本 5.0 开始支持类的定义和其他用户定义类型的正式语法。这允许开发人员和 IT 专业人士使用面向对象编程的概念来定义自定义类型,从而扩大 PowerShell 的适用范围。

本文为个人的学习笔记,参考官方文档,加入了一些理解,示例为本人实验时写的代码,可能不太严谨。如果有错误内容的话,还请多多指正!

概念

  • 类(Class) 是抽象的模板,定义了对象的结构和行为。

  • 对象(Object) 是根据类(Class)创建出来的实例(Instance),对象是类的具体实例。

  • 实例化是根据类(Class)创建对象(Object)的过程。

  • 实例成员是类(Class)的实例属性和实例方法,其中包含多个属性(Property)、构造函数(Constructor)、和方法(Method),它们的状态随着每个对象实例的不同而不同。

    每个实例都有独立的成员,各个实例的同名字段互不影响。

    也就是说,每个对象实例都有其自己的一套实例成员的副本

    只能通过类的创建实例访问属性和方法。

    • 类属性(Class_Property) 是在类范围中声明的变量。

      属性可以是任何内置类型,也可以是另一个类的实例。

      类可以具有零个或多个属性。

      类属性没有数量限制。

    • 类构造函数(Class_Constructor) 是用于根据类(Class)初始化新创建的对象(Object)的函数。

      构造函数使你能够在创建类实例时设置默认值验证对象逻辑

      构造函数与类具有相同的名称。

      构造函数可能具有参数来初始化新对象的数据成员。

      限制:

      • 构造函数没有输出类型。 他们无法使用 return 返回值。
      • 构造函数始终与类同名。
      • 无法直接调用构造函数。 它们仅在创建实例时运行。
      • 构造函数永远不会出现在 cmdlet 的 Get-Member 输出中。

      一个类可以定义零个或多个构造函数。

      如果未定义构造函数,则为该类提供默认的无参数构造函数。此构造函数将所有成员初始化为其默认值。 对象类型和字符串被赋予 null 值。

      定义构造函数时,不会创建默认的无参数构造函数。如果需要,请创建无参数构造函数。

    • 类方法(Class_Methods) 是定义类可以执行的操作(函数)。

      方法可以采用指定输入数据的参数。

      方法始终定义输出类型。

      如果方法未返回任何输出,则它必须具有 Void 输出类型。 如果方法未显式定义输出类型,则该方法的输出类型为 Void

      在类方法中,除语句中指定的 return 对象外,不会向管道发送任何对象。代码不会意外输出到管道。这与 PowerShell 函数处理输出的方式有根本的不同,在 PowerShell 中,所有内容都进入管道。

  • hidden 关键字 用于隐藏类成员。

    该成员仍可供用户访问,并且可在对象可用的所有范围内使用。

    隐藏成员在 Get-Member cmdlet 中隐藏(可以用 Get-Member -Force显示),不能在类定义之外使用 Tab 补全或 IntelliSense 显示。

    static 关键字仅适用于类成员,而不适用于类本身。

  • static 关键字 用于定义类成员为静态。

    静态属性始终可用,独立于类实例化。也就是说,静态属性可以在不创建对象的情况下直接访问。

    静态属性在类的所有实例之间共享。也就是说,静态属性可以作为全局变量使用。

    静态方法始终可用。也就是说,静态方法可以在不创建对象的情况下直接调用。

    所有静态属性在整个会话范围内都有效。

    自动 $this 变量在静态方法中不可用。

    PowerShell 中定义的类的静态属性是可修改的(Update-TypeData cmdlet),默认情况下是不可修改的。无法定义不可变的静态属性。

    static 关键字仅适用于类成员,而不适用于类本身。

  • 继承(Class_Inheritance) 是一种机制,它允许一个类继承另一个类的属性和方法。

    PowerShell类支持继承,这使你可以定义可重用(继承)、扩展或修改父类行为的子类。

    成员被继承的类称为基类(父类)。 继承基类成员的类称为派生类(子类)。可以通过创建派生自现有类的新类来扩展类。 派生类继承基类的属性和方法。可以根据需要添加或替代基类成员。

    PowerShell 仅支持单一继承。 类只能继承自单个类。 不过,继承是可传递的。这样一来,就可以为一组类型定义继承层次结构。 换句话说,类型 D 可以继承自类型 C,该类型继承自类型 B,后者继承自基类类型 A。由于继承是可传递的,A 类型的成员可用于类型 D。

    派生类可以访问基类的所有成员,但无法访问基类的私有成员。

    派生类不会继承基类的所有成员:不会继承静态构造函数、实例构造函数。

语法

定义类

1
2
3
4
5
6
class <类名> [ : [ <基类> ][ , <接口列表> ]] {
[[<属性>] [hidden] [static] <属性定义> ...]
[<类名>([<构造函数参数列表>])
{<构造函数语句列表>} ...]
[[<属性>] [hidden] [static] <方法定义> ...]
}

说明:

  1. 类名:定义一个类的名字。定义类名一般使用首字母大写的驼峰式命名。
  2. 基类:可选,指定该类继承自哪个基类。
  3. 接口列表:可选,指定该类实现哪些接口。
  4. 属性:修饰符,如访问级别控制(public, private, protected)或其他特性。
  5. hidden:表示隐藏父类中的同名成员。
  6. static:表示静态成员,不属于任何实例。
  7. 属性定义:定义类的属性或字段。
  8. 构造函数:定义类的构造函数,用于初始化新创建的对象。
  9. 构造函数参数列表:构造函数接受的参数列表。
  10. 构造函数语句列表:构造函数内部执行的语句。
  11. 方法定义:定义类的方法。

实例化类

  1. New-Object cmdlet

    1
    2
    [$<变量名> =] New-Object -TypeName <类名> [
    [-ArgumentList] <构造函数参数列表>]
    • 变量名:创建的对象将被赋值给这个变量。
    • New-Object:创建一个新的对象实例。
    • -TypeName:指定要创建的对象的类名。
    • -ArgumentList:可选参数列表,用于传递给构造函数。
  2. **[类名]::new()**:

    1
    [$<变量名> =] [<类名>]::new([<构造函数参数列表>])
    • 变量名:创建的对象将被赋值给这个变量。
    • ::new:调用类的构造函数。
    • 构造函数参数列表:构造函数的参数列表。

    使用 [类名]::new() 语法时,类名两边必须有括号([]())。括号表示 PowerShell 的类型定义。

  3. 类名哈希表

    1
    [$<变量名> =] [<类名>]@{[<类属性哈希表>]}
    • 变量名:创建的对象将被赋值给这个变量。
    • 类名:类名。
    • 类属性哈希表:使用哈希表来初始化类的属性。

    哈希表语法仅适用于具有不需要任何参数的默认构造函数的类。 它使用默认构造函数创建类的实例,然后将键值对分配给实例属性。 如果哈希表中的任何键不是有效的属性名称,PowerShell 将引发错误。

类属性

单行语法

1
[[<属性>]...] [<属性类型>] $<属性名称> [= <默认值>]

多行语法

1
2
3
[[<属性>]...]
[<属性类型>]
$<属性名称> [= <默认值>]
  1. 属性(Attributes)
    • [[<attribute>]...]:表示一个或多个属性(attributes)。这些属性可以用于修饰属性,提供额外的信息或行为。
    • 例如:[NoRunspaceAffinity()][ValidateRange(1, 10)]
  2. 属性类型(Property Type)
    • <property-type>:表示属性的数据类型。
    • 例如:[int][string][DateTime] 等。
  3. 属性名称(Property Name)
    • $<property-name>:表示属性的名称。
    • 例如:$MyProperty
  4. 默认值(Default Value)(可选):
    • = <default-value>:表示属性的默认值。
    • 例如:= 0= "default" 等。

类方法

单行语法

1
[[<属性>]...] [hidden] [static] [<输出类型>] <方法名称> ([<方法参数>]) { <方法体> }

多行语法

1
2
3
4
5
6
[[<属性>]...]
[hidden]
[static]
[<输出类型>] <方法名称> ([<方法参数>]) {
<方法体>
}
  1. 属性(Attributes)
    • [[<attribute>]...]:表示一个或多个属性(attributes)。这些属性可以用于修饰方法,提供额外的信息或行为。
    • 例如:[NoRunspaceAffinity()][ValidateRange(1, 10)]
  2. 隐藏(Hidden)
    • [hidden]:表示该方法是隐藏的,不会显示在对象的公共成员列表中。
  3. 静态(Static)
    • [static]:表示该方法是静态方法,可以直接通过类名调用,不需要创建类的实例。
  4. 输出类型(Output Type)
    • [<output-type>]:表示方法的返回类型。
    • 例如:[int][string][void] 等。
  5. 方法名称(Method Name)
    • <method-name>:表示方法的名称。
    • 例如:MyMethod
  6. 方法参数(Method Parameters)
    • ([<method-parameters>]):表示方法的参数列表。
    • 例如:([int] $param1, [string] $param2)
  7. 方法体(Body)
    • { <body> }:表示方法的具体实现代码块。
    • 例如:{ Write-Host "Hello, World!" }

示例

最小定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 定义一个名为 MadDog 的类
class MadDog {
[string]$Name
}
# 实例化一个 MadDog 对象
$dog = [MadDog]::new()
# 给 dog 对象的 Name 属性赋值
$dog.Name = "Yaya"
# 输出 dog 对象
$dog

# 输出:
Name
----
Yaya

包含实例成员的类

此示例定义了一个 MadDog 类,其中包含多个属性、构造函数和方法。 每个定义的成员都是实例成员,而不是静态成员。只能通过类的创建实例访问属性和方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class MadDog {
# 类属性
[string]$Name
[datetime]$Birthday

# 默认构造函数
MadDog() { $this.Init(@{}) }

# 哈希表构造函数
MadDog([hashtable]$Properties) { $this.Init($Properties) }

# 名字和生日构造函数
MadDog([string]$Name, [datetime]$Birthday) {
$this.Init(@{Name = $Name; Birthday = $Birthday })
}

# 共享实例化方法
[void] Init([hashtable]$Properties) {
foreach ($Property in $Properties.Keys) {
$this.$Property = $Properties.$Property
}
}

# 计算年龄
[timespan] GetAge() {
if (
$null -eq $this.Birthday -or $this.Birthday -eq [datetime]::MinValue
) { throw "Birthday 未定义" }

return (Get-Date) - $this.Birthday
}

# 返回字符串表示
[string] ToString() {
return "$($this.Name) 于 $($this.Birthday.Year) 年 $($this.Birthday.Month) 月 $($this.Birthday.Day) 日生,现在已经生活了 $($this.GetAge()) 天。"
}
}

实例化 MadDog 类的 dog 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$dog = [MadDog]::new("Yaya", "2017-01-01")

$dog
# Name Birthday
# ---- --------
# Yaya 2017/1/1 0:00:00


$dog.GetAge()
# Days : 2817
# Hours : 7
# Minutes : 10
# Seconds : 0
# Milliseconds : 801
# Ticks : 2434146008012020
# TotalDays : 2817.29862038428
# TotalHours : 67615.1668892228
# TotalMinutes : 4056910.01335337
# TotalSeconds : 243414600.801202
# TotalMilliseconds : 243414600801.202


$dog.ToString()
# Yaya 于 2017 年 1 月 1 日生,现在已经生活了 2817.07:11:35.7569411 天。

具有静态成员的类

此示例中的 DogList 类基于示例 2 中的 MadDog 类。虽然 DogList 类不能标记为静态本身,但实现仅定义 Dogs 静态属性和一组用于管理该属性的静态方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class DogList {
# 静态属性 Dogs,用于保存所有的狂犬列表
static [System.Collections.Generic.List[MadDog]] $Dogs

# 静态方法,用于初始化狂犬列表。在其他静态方法中调用以避免显式初始化。
# 这样做的目的是确保在调用任何其他静态方法之前,书籍列表已经被正确初始化。这使得调用者无需担心初始化问题,从而简化了使用过程。
static [void] Initialize() {
# Initialize() 方法是一个简单的调用 Initialize($false) 的方法
[DogList]::Initialize($false)
}

static [bool] Initialize([bool]$force) {
# Initialize([bool]$force) 方法根据 $force 参数决定是否强制重新初始化书籍列表。
if ([DogList]::Dogs.Count -gt 0 -and -not $force) { return $false }

[DogList]::Dogs = [System.Collections.Generic.List[MadDog]]::new()

return $true
}

# 确保狂犬有效,可以添加到列表中。
static [void] Validate([MadDog]$Dog) {
$Prefix = @(
'狂犬验证失败:书籍必须定义 Name 和 Birthday 属性,但是'
) -join ' '
if ($null -eq $Dog.Name) {
throw "$Prefix Name 属性未定义。"
}
if ($null -eq $Dog.Birthday) {
throw "$Prefix Birthday 属性未定义。"
}
}

# 静态方法,用于管理狂犬列表
# 如果该狂犬尚未在列表中,则将其添加到列表中。
static [void] Add([MadDog]$Dog) {
[DogList]::Initialize()
[DogList]::Validate($Dog)
if ([DogList]::Dogs.Contains($Dog)) {
throw "狂犬 $Dog 已存在于列表中。"
}

[DogList]::Dogs.Add($Dog)
}

# 静态方法,用于清空狂犬列表
static [void] Clear() {
[DogList]::Initialize($true)
[DogList]::Dogs.Clear()
}

# 使用过滤脚本块查找特定狂犬
static [MadDog] Find([scriptblock]$Filter) {
[DogList]::Initialize()
return [DogList]::Dogs.Find($Filter)
}

# 查找所有匹配过滤脚本块的狂犬
static [MadDog[]] FindAll([scriptblock]$Filter) {
[DogList]::Initialize()
return [DogList]::Dogs.FindAll($Filter)
}

# 删除特定狂犬
static [void] Remove([MadDog]$Dog) {
[DogList]::Initialize()
[DogList]::Dogs.Remove($Dog)
}

# 通过属性值删除狂犬
static [void] RemoveBy([string]$Property, [object]$Value) {
[DogList]::Initialize()
$Index = [DogList]::Dogs.FindIndex({
$args[0].$Property -eq $Value
}.GetNewClosure())
if ($Index -ge 0) {
[DogList]::Dogs.RemoveAt($Index)
}
}
}

定义 DogList 类后,可以将上一示例中的狂犬添加到列表中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 验证列表是否为空
$null -eq [DogList]::Dogs
# True

# 添加狂犬
[DogList]::Add($dog)

# 重复添加狂犬,验证 Validate() 方法
[DogList]::Add($dog)
# Exception: D:\temp\class.ps1:78:13
# Line |
# 78 | throw "狂犬 $Dog 已存在于列表中。"
# | ~~~~~~~~~~~~~~~~~~~~~~~~
# | 狂犬 Yaya 于 2017 年 1 月 1 日生,现在已经生活了 2817.08:15:06.0637525 天。 已存在于列表中。

[DogList]::Dogs
# Name Birthday
# ---- --------
# Yaya 2017/1/1 0:00:00

以下代码片段调用类的静态方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[DogList]::Add([MadDog]::new(@{
Name = "ToWong"
Birthday = "2015-01-01"
}))

[DogList]::Find({
$args[0].Birthday -gt '2016-01-01'
}).ToString()
# Yaya 于 2017 年 1 月 1 日生,现在已经生活了 2817.08:22:47.7292221 天。

[DogList]::FindAll({
$args[0].Birthday -gt '2014-01-01'
}).Name
# Yaya
# ToWong

[DogList]::Remove($dog)
[DogList]::Dogs.Name
# ToWong

[DogList]::RemoveBy('Name', 'ToWong')
"Names: $([DogList]::Dogs.Name)"
# Names:

[DogList]::Add($dog)
[DogList]::Add($dog)
# Exception: D:\temp\class.ps1:78:13
# Line |
# 78 | throw "狂犬 $Dog 已存在于列表中。"
# | ~~~~~~~~~~~~~~~~~~~~~~~~
# | 狂犬 Yaya 于 2017 年 1 月 1 日生,现在已经生活了 2817.08:26:24.6769138 天。 已存在于列表中。

包含和不使用 Runspace 相关性的类定义

PowerShell 允许定义类,而不考虑它们是否与当前运行空间相关。下面的示例定义了一个类,该类可以与任何 PowerShell 运行空间相关。

UnsafeClass 示例

ShowRunspaceId() 报告不同的线程 ID,但相同的运行空间 ID 的方法 [UnsafeClass]。 最终,会话状态已损坏,导致错误,例如 Global scope cannot be removed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 有运行空间相关性的类(默认)
class UnsafeClass {
static [object] ShowRunspaceId($val) {
return [PSCustomObject]@{
ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId
RunspaceId = [runspace]::DefaultRunspace.Id
}
}
}

$unsafe = [UnsafeClass]::new()

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

# ThreadId RunspaceId
# -------- ----------
# 26 4
# 29 4
# 29 4
# 31 4
# 31 4
# 32 4
# 32 4
# 35 4
# 28 4
# 28 4
# 24 4
# 24 4
# 35 4
# 32 4
# WriteError:
# Line |
# 3 | ($using:unsafe)::ShowRunspaceId($_)
# | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | Global scope cannot be removed.
# 41 4
# 42 4
# 42 4
# 40 4
# 40 4
# ......

此示例无限循环运行。 输入 Ctrl+C 可停止执行。

SafeClass 示例

[SafeClass]ShowRunspaceId() 方法报告不同的线程 Runspace ID。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 没有运行空间相关性(NoRunspaceAffinity)的类
[NoRunspaceAffinity()]
class SafeClass {
static [object] ShowRunspaceId($val) {
return [PSCustomObject]@{
ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId
RunspaceId = [runspace]::DefaultRunspace.Id
}
}
}

$safe = [SafeClass]::new()

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

# ThreadId RunspaceId
# -------- ----------
# 26 5
# 27 6
# 30 9
# 28 7
# 29 8
# 31 6
# 33 8
# 32 5
# 35 7
# 34 9
# 35 11
# 36 10
# 34 12
# 33 13
# 32 14

此示例无限循环运行。 输入 Ctrl+C 可停止执行。

具有自定义类型的类属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
enum LogLevel {
Debug
Info
Warning
Error
}
class Logger {
[string]$Message
[LogLevel]$Level = [LogLevel]::Info
[void] Write() {
Write-Host "[$($this.Level)]: $($this.Message)"
}
}

$logger = [Logger]::new()
$logger.Message = "Hello, World!"
$logger.Level = [LogLevel]::Debug
$logger.Write()
# [Debug]: Hello, World!

具有验证类型的类属性

using namespace System.Management.Automation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 定义 InstallPackage 类
class InstallPackage {
[ValidateNotNullOrEmpty()] [string]$Path
}
# 创建 installer 实例
$installer = [InstallPackage]::new()
# 尝试设置“Path”为空值
$installer.Path = ""
# 报错:设置“Path”时发生异常:“参数为 Null 或空。请提供一个不为 Null 或空的参数,然后重试该命令。”
# 所在位置 行:1 字符: 1
# + $installer.Path = ""
# + ~~~~~~~~~~~~~~~~~~~~
# + CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
# + FullyQualifiedErrorId : ExceptionWhenSetting
$installer.Path = $null
# 报错同上
$installer.Path = "C:\Program Files"
$installer
# Path
# ----
# C:\Program Files

具有显式默认值的类属性

1
2
3
4
5
6
7
8
9
10
11
12
class MadDog {
[string]$Name = "Yaya"
# 假设狗子是现在出生的
[DateTime]$Birthday = (Get-Date).Date
}

[MadDog]::new()
# Name Birthday
# ---- --------
# Yaya 2024/9/18 0:00:00
[MadDog]::new().Birthday -eq (Get-Date).Date
# True

隐藏类属性

不支持 PowerShell 5.1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class MadDog {
[string]$Name = "Yaya"
[DateTime]$Birthday = (Get-Date).Date
hidden [string]$Guid = (New-Guid).Guid
}

$dog = [MadDog]::new()

$dog
# Name Birthday
# ---- --------
# Yaya 2024/9/18 0:00:00

$dog.Guid
# d3b72879-dd18-40ca-8248-31375e486e76

$dog | Get-Member -MemberType Properties
# TypeName: MadDog

# Name MemberType Definition
# ---- ---------- ----------
# Birthday Property datetime Birthday {get;set;}
# Name Property string Name {get;set;}

# 使用 -Force 参数显示隐藏的类属性
$dog | Get-Member -MemberType Properties -Force
# TypeName: MadDog

# Name MemberType Definition
# ---- ---------- ----------
# pstypenames CodeProperty System.Collections.ObjectModel.Collection`1[[System.String, System.Private.CoreLib, Version=8…
# Birthday Property datetime Birthday {get;set;}
# Guid Property string Guid {get;set;}
# Name Property string Name {get;set;}

Static 类属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MadDog {
[string]$Name
[DateTime]$Birthday = (Get-Date).Date
hidden [string]$Guid = (New-Guid).Guid
static [MadDog[]]$Dogs = @()
MadDog() {
# 将当前实例添加到静态属性中
[MadDog]::Dogs += $this
}
}

"Dog Count: $([MadDog]::Dogs.Count)"
# Dog Count: 0

$dog1 = [MadDog] @{ Name = "Yaya" }
$dog2 = [MadDog] @{ Name = "ToWong" }

[MadDog]::Dogs | Select-Object -Property Name, Guid
# Name Guid
# ---- ----
# Yaya d8d2fd8c-24d3-49e6-bcef-86e43062a63b
# ToWong 68b2ac8e-8904-421a-8cfa-903d9737cbf7

派生类属性(继承)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 土狗类
class RuralDog {
static [string]$Breed = "Rural"
[string]$Name = "XiaoHua"
}

# 中华田园犬类=土狗类
class ChineseDog : RuralDog {}

# 秋田犬类=土狗类
class Akita : RuralDog {
[string]$Name = "Sakura"
}

# 狼=未定义品种土狗类
class Wolf : RuralDog {
[string] $Breed
[string] $Name
}

# 狂犬=超级土狗
class MadDog : ChineseDog {
static [string]$Breed = "SuperRural"
[string]$Name = "Yaya"
}


"土狗: $([RuralDog]::new().Name) - $([RuralDog]::Breed) "
# 土狗: XiaoHua - Rural

"中华田园犬: $([ChineseDog]::new().Name) - $([ChineseDog]::Breed) "
# 中华田园犬: XiaoHua - Rural

"秋田犬: $([Akita]::new().Name) - $([Akita]::Breed) "
# 秋田犬: Sakura - Rural

"狼: $([Wolf]::new().Name) - $([Wolf]::Breed) "
# 狼: -

"狂犬: $([MadDog]::new().Name) - $([MadDog]::Breed) "
# 狂犬: Yaya - SuperRural

具有参数的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class McDog {
[float] $
[float] $
[float] $

[float] 获取体积() { return $this.长 * $this.宽 * $this.高 }

[float] 获取质量([float]$密度) {
return $this.获取体积() * $密度
}
}

$Mc_YDog = [McDog]@{
长 = 2
宽 = 2
高 = 3
}

$Mc_YDog.获取质量(1.25)
# 15

不带输出的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class McDog {
[float] $
[float] $
[float] $

[float] 获取体积() {
$this.检验尺寸()
return $this.长 * $this.宽 * $this.高
}

[void] 检验尺寸() {
$不合规的属性 = @()
foreach ($属性 in @("长", "宽", "高")) {
if ($this.$属性 -lt 0) {
$不合规的属性 += $属性
}
}

if ($不合规的属性.Count -gt 0) {
$错误信息 = @(
'不合规的属性'
"('$($不合规的属性 -join "', '")'):"
"狗的尺寸必须为正数!"
) -join ' '
throw $错误信息
}
}
}

$Mc_YDog = [McDog]@{
长 = 2
宽 = -1
}

$Mc_YDog
# 长 宽 高
# -- -- --
# 2.00 -1.00 0.00

$Mc_YDog.获取体积()
# Exception:
# Line |
# 25 | throw $错误信息
# | ~~~~~~~~~~~
# | 不合规的属性 ('宽'): 狗的尺寸必须为正数!

具有重载的静态方法

方法签名和重载