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 $错误信息
#      |              ~~~~~~~~~~~
#      | 不合规的属性 ('宽'): 狗的尺寸必须为正数!

具有重载的静态方法

方法签名和重载