about_Classes_Properties
簡短描述
描述如何定義 PowerShell 類別的屬性。
詳細描述
屬性是包含數據的類別成員。 屬性會在類別範圍中宣告為變數。 屬性可以是任何內建類型或另一個類別的實例。 類別可以零個或多個屬性。 類別沒有屬性計數上限。
類別屬性可以有任意數目的屬性,包括 隱藏 和 靜態 屬性。 每個屬性定義都必須包含 屬性的類型。 您可以定義屬性的預設值。
語法
類別屬性使用下列語法:
單行語法
[[<attribute>]...] [<property-type>] $<property-name> [= <default-value>]
多行語法
[[<attribute>]...]
[<property-type>]
$<property-name> [= <default-value>]
範例
範例 1 - 最小類別屬性
ExampleProject1 類別的屬性使用內建類型,而不需要任何屬性或預設值。
class ExampleProject1 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
}
[ExampleProject1]::new()
$null -eq ([ExampleProject1]::new()).Name
Name :
Size : 0
Completed : False
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
True
Name 和 Assignee 屬性的預設值是$null
因為它們的類型為字元串,這是參考類型。 其他屬性具有其定義類型的預設值,因為它們是實值類型屬性。 如需屬性預設值的詳細資訊,請參閱 預設屬性值。
範例 2 - 具有自定義類型的類別屬性
ExampleProject2 的屬性包含範例Project2 類別之前在PowerShell中定義的自定義列舉和類別。
enum ProjectState {
NotTriaged
ReadyForWork
Committed
Blocked
InProgress
Done
}
class ProjectAssignee {
[string] $DisplayName
[string] $UserName
[string] ToString() {
return "$($this.DisplayName) ($($this.UserName))"
}
}
class ExampleProject2 {
[string] $Name
[int] $Size
[ProjectState] $State
[ProjectAssignee] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
}
[ExampleProject2]@{
Name = 'Class Property Documentation'
Size = 8
State = 'InProgress'
Assignee = @{
DisplayName = 'Mikey Lombardi'
UserName = 'michaeltlombardi'
}
StartDate = '2023-10-23'
DueDate = '2023-10-27'
}
Name : Class Property Documentation
Size : 8
State : InProgress
Assignee : Mikey Lombardi (michaeltlombardi)
StartDate : 10/23/2023 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 10/27/2023 12:00:00 AM
範例 3 - 具有驗證屬性的類別屬性
ExampleProject3 類別會將 Size 屬性定義為必須大於或等於 0 且小於或等於 16 的整數。 它會使用 ValidateRange 屬性來限制值。
class ExampleProject3 {
[string] $Name
[ValidateRange(0, 16)] [int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
}
$project = [ExampleProject3]::new()
$project
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
當 ExampleProject3 具現化時,Size 預設為 0。 將屬性設定為有效範圍內的值會更新值。
$project.Size = 8
$project
Name :
Size : 8
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
當 Size 設定為超出範圍的無效值時,PowerShell 會引發例外狀況,而且值不會變更。
$project.Size = 32
$project.Size = -1
$project
SetValueInvocationException:
Line |
1 | $project.Size = 32
| ~~~~~~~~~~~~~~~~~~
| Exception setting "Size": "The 32 argument is greater than the
| maximum allowed range of 16. Supply an argument that is less than
| or equal to 16 and then try the command again."
SetValueInvocationException:
Line |
2 | $project.Size = -1
| ~~~~~~~~~~~~~~~~~~
| Exception setting "Size": "The -1 argument is less than the minimum
| allowed range of 0. Supply an argument that is greater than or
| equal to 0 and then try the command again."
Name :
Size : 8
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
範例 4 - 具有明確預設值的類別屬性
ExampleProject4 類別會將 StartDate 屬性的值預設為目前的日期。
class ExampleProject4 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate = (Get-Date).Date
[datetime] $EndDate
[datetime] $DueDate
}
[ExampleProject4]::new()
[ExampleProject4]::new().StartDate -eq (Get-Date).Date
Name :
Size : 0
Completed : False
Assignee :
StartDate : 10/23/2023 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
True
範例 5 - Hidden 類別屬性
ExampleProject5 類別的 Guid 屬性具有 hidden
關鍵詞。 Guid 屬性不會顯示在 類別的預設輸出中,也不會顯示在 所Get-Member
傳回的屬性清單中。
class ExampleProject5 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
hidden [string] $Guid = (New-Guid).Guid
}
$project = [ExampleProject5]::new()
"Project GUID: $($project.Guid)"
$project
$project | Get-Member -MemberType Properties | Format-Table
Project GUID: c72cef84-057c-4649-8940-13490dcf72f0
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
TypeName: ExampleProject5
Name MemberType Definition
---- ---------- ----------
Assignee Property string Assignee {get;set;}
Completed Property bool Completed {get;set;}
DueDate Property datetime DueDate {get;set;}
EndDate Property datetime EndDate {get;set;}
Name Property string Name {get;set;}
Size Property int Size {get;set;}
StartDate Property datetime StartDate {get;set;}
範例 6 - Static 類別屬性
ExampleProject6 類別會將靜態 Projects 屬性定義為所有已建立項目的清單。 類別的預設建構函式會將新實例新增至專案清單。
class ExampleProject6 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
hidden [string] $Guid = (New-Guid).Guid
static [ExampleProject6[]] $Projects = @()
ExampleProject6() {
[ExampleProject6]::Projects += $this
}
}
"Project Count: $([ExampleProject6]::Projects.Count)"
$project1 = [ExampleProject6]@{ Name = 'Project_1' }
$project2 = [ExampleProject6]@{ Name = 'Project_2' }
[ExampleProject6]::Projects | Select-Object -Property Name, Guid
Project Count: 0
Name Guid
---- ----
Project_1 75e7c8a0-f8d1-433a-a5be-fd7249494694
Project_2 6c501be4-e68c-4df5-8fce-e49dd8366afe
範例 7 - 在建構函式中定義屬性
ExampleProject7 類別會使用 Update-TypeData
Cmdlet 在靜態類別建構函式中定義 Duration 腳本屬性。 Update-TypeData
使用 或 Add-Member
Cmdlet 是定義 PowerShell 類別進階屬性的唯一方法。
Duration 屬性會傳回 的值$null
,除非已設定 StartDate 和 EndDate 屬性,而且 StartDate 定義為早於 EndDate。
class ExampleProject7 {
[string] $Name
[int] $Size
[bool] $Completed
[string] $Assignee
[datetime] $StartDate
[datetime] $EndDate
[datetime] $DueDate
static [hashtable[]] $MemberDefinitions = @(
@{
MemberName = 'Duration'
MemberType = 'ScriptProperty'
Value = {
[datetime]$UnsetDate = 0
$StartNotSet = $this.StartDate -eq $UnsetDate
$EndNotSet = $this.EndDate -eq $UnsetDate
$StartAfterEnd = $this.StartDate -gt $this.EndDate
if ($StartNotSet -or $EndNotSet -or $StartAfterEnd) {
return $null
}
return $this.EndDate - $this.StartDate
}
}
)
static ExampleProject7() {
$TypeName = [ExampleProject7].Name
foreach ($Definition in [ExampleProject7]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
ExampleProject7() {}
ExampleProject7([string]$Name) {
$this.Name = $Name
}
}
$Project = [ExampleProject7]::new()
$Project
$null -eq $Project.Duration
Duration :
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/0001 12:00:00 AM
EndDate : 1/1/0001 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
True
ExampleProject7 類別實例的預設檢視包含持續時間。 因為未設定 StartDate 和 EndDate 屬性,Duration 屬性為 $null
。
$Project.StartDate = '2023-01-01'
$Project.EndDate = '2023-01-08'
$Project
Duration : 7.00:00:00
Name :
Size : 0
Completed : False
Assignee :
StartDate : 1/1/2023 12:00:00 AM
EndDate : 1/8/2023 12:00:00 AM
DueDate : 1/1/0001 12:00:00 AM
正確設定屬性后, Duration 屬性會傳回代表專案執行時間長度的時間範圍。
默認屬性值
每個類別屬性都有隱含的預設值,視屬性的類型而定。
如果屬性是 參考型別,例如字串或物件,則隱含的預設值為 $null
。 如果屬性是 實值型別,例如數位、布爾值或列舉,則屬性會根據類型具有預設值:
- 數值類型,例如整數和浮點數,預設為
0
- 布爾值預設為
$false
- 列舉預設為
0
,即使是列舉也不會定義 的0
標籤。
如需 .NET 中預設值的詳細資訊,請參閱 C# 類型的預設值(C# 參考)。
若要定義屬性的明確預設值,請使用指派給預設值來宣告 屬性。
例如,ProjectTask 類別的這個定義會定義 Guid 屬性的明確預設值,將隨機 GUID 指派給每個新實例。
class ProjectTask {
[string] $Name
[string] $Description
[string] $Guid = (New-Guid).Guid
}
[ProjectTask]::new()
Name Description Guid
---- ----------- ----
aa96350c-358d-465c-96d1-a49949219eec
隱藏和靜態屬性也可以有預設值。
隱藏的屬性
您可以使用 關鍵詞宣告類別的屬性,以隱藏類別 hidden
的屬性。
隱藏的類別屬性包括:
- 不包含在 類別的預設輸出中。
- Cmdlet 所
Get-Member
傳回的類別成員清單中未包含。 若要使用Get-Member
顯示隱藏的屬性,請使用 Force 參數。 - 除非完成發生在定義隱藏屬性的類別中,否則不會顯示在索引標籤完成或 IntelliSense 中。
- 類別的公用成員。 您可以存取和修改它們。 隱藏屬性不會讓它成為私人屬性。 它只會隱藏如先前點中所述的屬性。
如需 關鍵詞的詳細資訊 hidden
,請參閱 about_Hidden。
靜態屬性
您可以使用 關鍵詞宣告 static
屬性,將 屬性定義為屬於類別本身,而不是 類別的實例。 靜態類別屬性:
- 一律可供使用,與類別具現化無關。
- 會在類別的所有實例之間共用。
- 一律可供使用。
- 可修改。 靜態屬性可以更新。 根據預設,它們不可變。
- 整個工作階段範圍的即時處理。
重要
PowerShell 中定義的類別靜態屬性不可變。 他們可以
衍生類別屬性
當類別衍生自基類時,它會繼承基類的屬性。 在基類上定義的任何屬性,包括隱藏的屬性,都可以在衍生類別上使用。
衍生類別可以藉由在類別定義中重新定義繼承屬性來覆寫繼承的屬性。 衍生類別上的 屬性會使用重新定義的型別和預設值,如果有的話。 如果繼承的屬性定義了預設值,且重新定義的屬性沒有,則繼承的屬性沒有預設值。
如果衍生類別未覆寫靜態屬性,則透過衍生類別存取靜態屬性會存取基類的靜態屬性。 透過衍生類別修改屬性值會修改基類上的值。 未覆寫靜態屬性的任何其他衍生類別也會使用基類上的 屬性值。 更新未覆寫屬性之類別中繼承之靜態屬性的值,可能會對衍生自相同基類的類別產生非預期的影響。
下列範例顯示衍生類別上靜態和實例屬性的行為。
class BaseClass {
static [string] $StaticProperty = 'Static'
[string] $InstanceProperty = 'Instance'
}
class DerivedClassA : BaseClass {}
class DerivedClassB : BaseClass {}
class DerivedClassC : DerivedClassB {
[string] $InstanceProperty
}
class DerivedClassD : BaseClass {
static [string] $StaticProperty = 'Override'
[string] $InstanceProperty = 'Override'
}
"Base instance => $([BaseClass]::new().InstanceProperty)"
"Derived instance A => $([DerivedClassA]::new().InstanceProperty)"
"Derived instance B => $([DerivedClassB]::new().InstanceProperty)"
"Derived instance C => $([DerivedClassC]::new().InstanceProperty)"
"Derived instance D => $([DerivedClassD]::new().InstanceProperty)"
Base instance => Instance
Derived instance A => Instance
Derived instance B => Instance
Derived instance C =>
Derived instance D => Override
DerivedClassC 的 InstanceProperty 是空字串,因為類別會重新定義 屬性,而不設定預設值。 針對 DerivedClassD ,值是因為 Override
類別會以該字串作為預設值重新定義 屬性。
"Base static => $([BaseClass]::StaticProperty)"
"Derived static A => $([DerivedClassA]::StaticProperty)"
"Derived static B => $([DerivedClassB]::StaticProperty)"
"Derived static C => $([DerivedClassC]::StaticProperty)"
"Derived static D => $([DerivedClassD]::StaticProperty)"
Base static => Static
Derived static A => Static
Derived static B => Static
Derived static C => Static
Derived static D => Override
除了 DerivedClassD 之外,衍生類別的靜態屬性值與基類相同,因為它們不會重新定義屬性。 這甚至適用於 DerivedClassC,其繼承自 DerivedClassB ,而不是直接從 BaseClass 繼承。
[DerivedClassA]::StaticProperty = 'Updated from A'
"Base static => $([BaseClass]::StaticProperty)"
"Derived static A => $([DerivedClassA]::StaticProperty)"
"Derived static B => $([DerivedClassB]::StaticProperty)"
"Derived static C => $([DerivedClassC]::StaticProperty)"
"Derived static D => $([DerivedClassD]::StaticProperty)"
Base static => Updated from A
Derived static A => Updated from A
Derived static B => Updated from A
Derived static C => Updated from A
Derived static D => Override
透過 DerivedClassA 存取及修改 StaticProperty 時,變更的值會影響 DerivedClassD 以外的每個類別。
如需類別繼承的詳細資訊,包括完整的範例,請參閱 about_Classes_Inheritance。
使用屬性屬性
PowerShell 包含數個屬性類別,可用來增強數據類型資訊,並驗證指派給屬性的數據。 驗證屬性可讓您測試提供給屬性的值符合定義的需求。 驗證會在指派值的那一刻觸發。
如需可用屬性的詳細資訊,請參閱 about_Functions_Advanced_Parameters。
使用 Update-TypeData 定義實例屬性
除了直接在類別定義中宣告屬性之外,您還可以使用 Update-TypeData
Cmdlet 在靜態建構函式中定義類別實例的屬性。
使用此代碼段作為模式的起點。 視需要取代角括弧中的佔位元文字。
class <ClassName> {
static [hashtable[]] $MemberDefinitions = @(
@{
MemberName = '<PropertyName>'
MemberType = '<PropertyType>'
Value = <ValueDefinition>
}
)
static <ClassName>() {
$TypeName = [<ClassName>].Name
foreach ($Definition in [<ClassName>]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
}
提示
Cmdlet Add-Member
可以將屬性和方法新增至非靜態建構函式中的類別,但每次呼叫建構函式時都會執行 Cmdlet。 在 Update-TypeData
靜態建構函式中使用 可確保將成員加入類別的程式代碼只需要在會話中執行一次。
只有在無法使用 Update-TypeData
定義屬性時,才能將屬性新增至非靜態建構函式中的 類別,例如只讀屬性。
定義別名屬性
在類別屬性宣告上使用 Alias 屬性時沒有任何作用。 PowerShell 只會使用該屬性來定義 Cmdlet、參數和函式名稱的別名。
若要定義類別屬性的別名,請搭配 MemberType 使用AliasProperty
Update-TypeData
。
例如,OperablePair 類別的定義會分別使用 LeftHandSide 和 RightHandSide 別名定義兩個整數屬性 x 和 y。
class OperablePair {
[int] $x
[int] $y
static [hashtable[]] $MemberDefinitions = @(
@{
MemberType = 'AliasProperty'
MemberName = 'LeftHandSide'
Value = 'x'
}
@{
MemberType = 'AliasProperty'
MemberName = 'RightHandSide'
Value = 'y'
}
)
static OperablePair() {
$TypeName = [OperablePair].Name
foreach ($Definition in [OperablePair]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
OperablePair() {}
OperablePair([int]$x, [int]$y) {
$this.x = $x
$this.y = $y
}
# Math methods for the pair of values
[int] GetSum() { return $this.x + $this.y }
[int] GetProduct() { return $this.x * $this.y }
[int] GetDifference() { return $this.x - $this.y }
[float] GetQuotient() { return $this.x / $this.y }
[int] GetModulus() { return $this.x % $this.y }
}
定義別名后,用戶可以使用任一名稱來存取屬性。
$pair = [OperablePair]@{ x = 8 ; RightHandSide = 3 }
"$($pair.x) % $($pair.y) = $($pair.GetModulus())"
$pair.LeftHandSide = 3
$pair.RightHandSide = 2
"$($pair.x) x $($pair.y) = $($pair.GetProduct())"
8 % 3 = 2
3 x 2 = 6
定義匯出屬性
若要定義參考其他屬性值的屬性,請使用 Update-TypeData
Cmdlet 搭配 ScriptProperty
MemberType。
例如,預算類別的這個定義會將 Expenses 和 Revenues 屬性定義為浮點數的陣列。 它會使用 Update-TypeData
Cmdlet 來定義總費用、總收入和凈收入的計算屬性。
class Budget {
[float[]] $Expenses
[float[]] $Revenues
static [hashtable[]] $MemberDefinitions = @(
@{
MemberType = 'ScriptProperty'
MemberName = 'TotalExpenses'
Value = { ($this.Expenses | Measure-Object -Sum).Sum }
}
@{
MemberType = 'ScriptProperty'
MemberName = 'TotalRevenues'
Value = { ($this.Revenues | Measure-Object -Sum).Sum }
}
@{
MemberType = 'ScriptProperty'
MemberName = 'NetIncome'
Value = { $this.TotalRevenues - $this.TotalExpenses }
}
)
static Budget() {
$TypeName = [Budget].Name
foreach ($Definition in [Budget]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
Budget() {}
Budget($Expenses, $Revenues) {
$this.Expenses = $Expenses
$this.Revenues = $Revenues
}
}
[Budget]::new()
[Budget]@{
Expenses = @(2500, 1931, 3700)
Revenues = @(2400, 2100, 4150)
}
TotalExpenses : 0
TotalRevenues : 0
NetIncome : 0
Expenses :
Revenues :
TotalExpenses : 8131
TotalRevenues : 8650
NetIncome : 519
Expenses : {2500, 1931, 3700}
Revenues : {2400, 2100, 4150}
使用自訂 get 和 set 邏輯定義屬性
PowerShell 類別屬性無法直接定義自定義 getter 和 setter 邏輯。 您可以使用 關鍵詞來定義支援屬性, hidden
並使用 Update-TypeData
來定義具有自定義邏輯的可見屬性,以取得和設定值,來近似這項功能。
依照慣例,使用底線前置詞定義隱藏支援屬性名稱,並使用駱駝式大小寫。 例如,而不是 TaskCount
,將隱藏支援屬性 _taskCount
命名為 。
在此範例中 ,ProjectSize 類別會定義名為 _value 的隱藏整數屬性。 它會使用 自定義邏輯來定義 Value , ScriptProperty
以取得和設定 _value 屬性。 setter scriptblock 會處理將專案的字串表示轉換成正確的大小。
class ProjectSize {
hidden [ValidateSet(0, 1, 2, 3)] [int] $_value
static [hashtable[]] $MemberDefinitions = @(
@{
MemberType = 'ScriptProperty'
MemberName = 'Value'
Value = { $this._value } # Getter
SecondValue = { # Setter
$ProposedValue = $args[0]
if ($ProposedValue -is [string]) {
switch ($ProposedValue) {
'Small' { $this._value = 1 ; break }
'Medium' { $this._value = 2 ; break }
'Large' { $this._value = 3 ; break }
default { throw "Unknown size '$ProposedValue'" }
}
} else {
$this._value = $ProposedValue
}
}
}
)
static ProjectSize() {
$TypeName = [ProjectSize].Name
foreach ($Definition in [ProjectSize]::MemberDefinitions) {
Update-TypeData -TypeName $TypeName @Definition
}
}
ProjectSize() {}
ProjectSize([int]$Size) { $this.Value = $Size }
ProjectSize([string]$Size) { $this.Value = $Size }
[string] ToString() {
$Output = switch ($this._value) {
1 { 'Small' }
2 { 'Medium' }
3 { 'Large' }
default { 'Undefined' }
}
return $Output
}
}
定義自定義 getter 和 setter 之後,您可以將 Value 屬性設定為整數或字串。
$size = [ProjectSize]::new()
"The initial size is: $($size._value), $size"
$size.Value = 1
"The defined size is: $($size._value), $size"
$Size.Value += 1
"The updated size is: $($size._value), $size"
$Size.Value = 'Large'
"The final size is: $($size._value), $size"
The initial size is: 0, Undefined
The defined size is: 1, Small
The updated size is: 2, Medium
The final size is: 3, Large
限制
PowerShell 類別屬性具有下列限制:
靜態屬性一律為可變動。 PowerShell 類別無法定義不可變的靜態屬性。
因應措施:無。
屬性無法使用 ValidateScript 屬性,因為類別屬性屬性自變數必須是常數。
因應措施:定義繼承自 ValidateArgumentsAttribute 類型的類別,並改用該屬性。
直接宣告的屬性無法定義自定義 getter 和 setter 實作。
因應措施:定義隱藏的屬性,並使用
Update-TypeData
來定義可見的 getter 和 setter 邏輯。屬性無法使用 Alias 屬性。 屬性僅適用於參數、Cmdlet 和函式。
因應
Update-TypeData
措施:使用 Cmdlet 在類別建構函式中定義別名。當 PowerShell 類別使用
ConvertTo-Json
Cmdlet 轉換成 JSON 時,輸出 JSON 會包含所有隱藏的屬性及其值。因應措施:無