PowerShell 是一種物件導向語言。當你執行命令並在螢幕上看到輸出時,那些都是物件。物件並不是從空氣中產生的;開發者會使用類別來創建它們,或者更具體地說,使用類別來實例化它們。PowerShell 類別表示這些物件的定義或模式。
雖然你可能熟悉使用像 New-Object
這樣的命令來創建物件,並使用 pscustomobject
類型加速器,但這些並不是真正的「新」物件。這些方法產生的物件是特定的 類型。PowerShell 類別定義了這個 類型。
在本教程中,你將學習如何開始使用 PowerShell 類別。你將創建自己的第一個類別,了解如何從類別創建物件,並為類別添加屬性和方法。
如果想了解物件、屬性和方法等術語的背景,請參考博文 回到基礎:理解 PowerShell 物件。
前提條件
創建 你的第一個類別和物件
在你深入了解 PowerShell 類別的細節之前,你應該先簡單創建一個類別。稍後你將學習更高級的主題。
創建您的第一個類別會感覺有點像創建一個函數。基本語法是相同的。類別是從定義中創建的,就像函數一樣。不過,與函數不同的是,第一行不是以function
開始,後面是函數名稱,而是以class
開始,後面是您對象類型的名稱。
下面你會看到一個名為student的類別的基本結構。
類別有像描述該類別的屬性的參數一樣的屬性。下面的例子顯示了一個名為student的類別,有兩個屬性:FirstName
和LastName
。
當您定義一個屬性時,應該總是定義一個類型,為屬性值設置一個特定的“模式”。在下面的例子中,兩個屬性都被定義為strings。
您應該總是定義屬性類型。稍後您將明白為什麼。
在定義類別後,創建一個對象或實例化一個對象。有多種從類別實例化對象的方法;一種常見的方法是使用類型加速器,如[student]
,代表該類別,後面跟著每個類別都帶有的默認方法,稱為new()
。
使用類型加速器快捷方式與使用New-Object
命令創建對象相同。
一旦您从该类创建了一个对象,然后为属性分配值。下面的示例是为FirstName
和LastName
属性分配Tyler
和Muir
的值。
创建对象并为属性分配值后,通过调用分配对象的变量来检查对象,如下所示。

现在,您从类创建了一个对象,像在PowerShell中处理任何其他对象一样,将该对象传递给Get-Member
cmdlet以对其进行检查。您可以在下面看到$student1
变量中保存的对象的类型为student。
类名将始终与对象类型相关联。
请注意,Get-Member
返回四个方法和两个属性。属性可能看起来很熟悉,但方法肯定不是。PowerShell默认添加了某些方法,但您也可以添加自己的方法或甚至修改默认方法。

创建方法
在上面的示例中,您看到对象上有一些默认方法,但很有可能您会想要创建自己的方法。要做到这一点,您必须在类定义内部定义一个或多个方法。
A method definition looks like below with an output type that defines what type of object is returned from this method, the name of the method, and the code to execute inside of a scriptblock.
请注意名称后面的括号()
。这是您可以定义方法参数的地方(稍后介绍)。方法参数允许您像处理函数参数一样更改方法的功能。
如果您之前编写并运行过PowerShell函数,那么方法脚本块应该会感觉很熟悉,但是有一些关于方法的特殊规则您应该知道。
return
是强制的
PowerShell函数将通过在函数中的任何位置放置对象来返回对象,就像下面的例子一样。
然而,与函数不同,如果方法返回一个对象,您必须使用如下所示的return
结构。
使用$this
变量
方法与函数的另一个区别是$this
变量。$this
变量在方法内部定义,引用当前对象的属性或其他方法。
下面是一个名为GetName()
的方法的示例,该方法已添加到student
类中,该方法连接FirstName
和LastName
属性的值并返回它们。
现在您可以使用点表示法调用GetName()
方法,如下所示。如果您先前为FirstName
和LastName
分配了值,GetName()
将返回它们。

将参数添加到方法
在上面的例子中,当您运行$student1.GetName()
这一行时,您是按原样调用GetName()
方法的。在括号内,您可以定义与函数类似的参数。
GetName()
方法只返回为 FirstName
和 LastName
属性设置的任何值。但如果您宁愿有一个方法来 设置 GetName()
然后可以 获取 的属性值呢?在这种情况下,您需要定义方法参数。
通过在方法参数括号中包含一个或多个以逗号分隔的参数来定义方法参数,如下所示。
请注意
[void]
输出类型。每当一个方法不输出任何内容时,您不需要return
结构,应该将输出类型定义为[void]
以告诉 PowerShell 该方法不返回任何内容。
例如,也许 SetName()
方法接受一个完整的姓名(名字和姓氏)。如果是这样,在脚本块中,您可以拆分此字符串并分配名字和姓氏。
通过将 SetName()
方法插入到 student
类中,现在它的样子如下。
现在,您可以将一个完整的姓名作为参数传递给 SetName()
方法,从而设置当前对象的 FirstName
和 LastName
属性。

方法重载
也许您想要为一个方法定义不同的参数集。类似于在函数和 cmdlet 中工作的参数集,您可以定义不同的参数“上下文”或方法签名。参数集 的工作方式,您可以定义不同的参数“上下文”或方法签名。
也許您想通過將完整姓名傳遞給SetName()
方法或分別傳遞名和姓來設置FirstName
和LastName
參數。您不必選擇;您可以使用方法簽名定義它們兩者。
在一個類中定義多個方法簽名時,這被稱為重載。
重複使用前一節的示例,您可以為SetName()
方法創建一個重載,以接受兩個字符串而不是一個。當您傳遞兩個字符串而不是一個時,SetName()
方法會假定第一個字符串是FirstName
,第二個字符串是LastName
。通過該重載,該類將如下所示。

類構造函數
每當您使用new()
方法或其他方式實例化對象時,您可以告訴 PowerShell 執行一些稱為構造函數的用戶定義代碼。構造函數就像方法一樣,但當 PowerShell 實例化對象時會自動運行它們。自動
每個類都有一個默認構造函數。該默認構造函數沒有太多功能;它只負責實例化對象。您可以通過查看New
方法的輸出來查看默認構造函數。您可以看到下面這行返回一個new()
方法。

構造函數重載
或許您想在創建對象時為 FirstName
和 LastName
屬性設置值,而不是使用典型的點表示法。 在這種情況下,您可以創建一個帶有參數的構造函數,然后調用 SetName()
。
下面是 student
類的構造函數示例。 請注意,構造函數沒有特定的名稱,也沒有輸出類型的前綴。 構造函數始終使用與類相同的名稱。
在構造函數中調用現有方法允許我們重複使用我們已經編寫的方法來處理設置變量。
然后,您將看到將該構造函數添加到 student
類中。
當您實例化一個新的 student
對象並傳入字符串參數時,該對象的屬性將立即具有預期的值。

現在您可以再次看到帶有 [student]::New
的重載構造函數。 請注意,新的重載構造函數定義了一個 Name
參數。

定義默認和重載構造函數
現在您的 student
類上有了一個重載的構造函數,PowerShell 覆蓋了默認的構造函數。 但是,您可以通過手動創建一個沒有參數的構造函數來恢復它。
您可以在下面的 student
類中看到它的樣子。
現在再次檢查構造函數。 您現在會看到兩個構造函數都出現了。

類繼承
和其他面向对象的语言一样,你可以用多个类在 PowerShell 中建立层次结构。每个类都可以有“父类”和“子类”,从较不具体、更通用的目的开始,并增加特定性。
例如,我们的student
类表示一位大学生(子类/具体)。这位大学生是一个人(父类/通用)。这两个概念是相关的,并形成了一个层次结构。
A child class can inherit a parent class which means it can hold all properties and methods (members) defined via a parent class. We know that a person
class may have properties like eye_color
, height
, and weight
and perhaps a method called SetHeight()
.
如果一个学生是一个人,那么这个学生仍然具有那些属性和方法。在student
类上实现那些person
类已经有的成员将会重复努力。你可以定义类继承以自动在student
类上定义person
类的所有成员。
如果现在还不明白这一点,待我们进行演示时就会明白了。
类继承演示
首先,复制你之前创建的student
类,移除构造函数,并将其重命名为person
类。你的person
类应该像下面的类一样。
A student, of course, has a first name and last name, but the class can be described more accurately by labeling it as a person. When creating a more “generic” class like this, you can create more specific “child” classes from it.
现在,创建一些表示人但具有更具体角色的类。例如,在下面的代码片段中,你现在有一个teacher
类和一个student
类。
目前,teacher
类和student
类与person
类相互独立。它们之间没有关系,也无法继承person
类的任何成员。让我们改变这一点。
現在通過將teacher
和student
類定義為person
類的“子”類來定義層次結構。您可以通過在類名後附加冒號(:
)並跟隨父類名稱來定義繼承,如下所示。
您的整個類腳本現在應該如下所示:
在這一點上,當您從teacher
或student
類實例化對象時,這兩個類將擁有與person
類相同的成員。

帶構造函數的繼承
如您所見,類方法通過類繼承而繼承。這種行為可能會讓您認為構造函數會遵循相同的邏輯,但您錯了。構造函數不會被繼承,並且所有子類的構造函數必須在每個子類中單獨定義。
例如,也許您剛剛為person
類定義了一個重載的構造函數,但沒有為teacher
類定義構造函數,如下所示。
然後,您定義了一個子類,例如teacher
,並試圖從中創建沒有參數的對象,如下所示。請注意,PowerShell返回錯誤,因為在teacher
類內沒有定義無參數的構造函數。

A constructor is not necessary in a child class if you’re only using it as a template. Alternatively, if you want to use the parent class as its own standalone class and as a parent class you can include constructors. But you have to make sure that the parent class has a constructor that matches the ones in the child classes.
類成員屬性
就像PowerShell命令參數一樣,類可以有成員屬性。這些屬性修改每個成員的行為。
隱藏成員
如果您只想在內部使用類成員而不希望用戶讀取或寫入它,則將成員設置為隱藏。例如,您可能有一個只由其他方法使用的方法。沒有必要將該方法公開給用戶。
要定義一個隱藏的成員,請使用以下示例中所示的hidden
屬性。
現在,當您使用Get-Member
檢查所有物件成員時,該屬性不會顯示出來。

將類成員設置為隱藏不會限制對值的訪問,它只是將其隱藏起來。您不應該隱藏屬性來存儲敏感數據。
靜態成員
回想之前,本教程使用“實例化”一詞來描述從類創建對象。當您實例化一個對象時,該對象將具有類定義的所有屬性和方法。但這並不總是這樣的。
有時,您不需要實例化整個對象的開銷。相反,您需要快速引用單個類成員。在這種情況下,您可以將類成員設置為靜態。
與hidden
屬性一樣,使用以下示例中所示的static
關鍵字來定義靜態類成員。
與常規類成員不同,PowerShell不會從靜態類成員創建屬性和方法。當您將類成員定義為靜態時,像隱藏成員一樣,使用Get-Member
時它不會顯示出來。

例如,也许您想将大学课程名称与student
类相关联,并定义学生可以参加的大学课程的最大数量。为此,您创建一个Classes
数组成员和一个MaxClassCount
成员。
由于用户很少需要更改MaxClassCount
成员,您决定将其定义为静态的。
最后,您创建一个AddClass()
方法来将课程添加到学生的课程表中,但仅在小于MaxClassCount
时才添加。
现在,当您尝试创建一个新的student
对象并为其分配太多的大学课程时,PowerShell只会分配最多的课程,这个最多为七个。

您可以随时更改静态成员的值。例如,如果您想将
MaxClassCount
成员的值从7更改为5,您可以使用[student]::MaxClassCount = 5
来更改该值。在这个例子中,更改值不会反过来删除超出限制的课程。
结论
PowerShell类模糊了脚本语言和编程语言之间的界限。类是定义对象关系、添加与对象交互和格式化对象的方式的绝佳方法,这些通常只能通过编写专门的函数来实现。