about_Member-Access_Enumeration
簡短描述
描述當使用成員存取運算符時對集合進行自動列舉。
詳細描述
PowerShell 會維護可列舉的類型清單。 從 PowerShell 3.0 開始,成員存取列舉 功能可改善在可列舉的集合物件上使用成員存取運算符 (.
) 的便利性。
成員存取列舉可協助您撰寫更簡單且較短的程序代碼。 您可以對集合物件 ForEach-Object
使用成員存取運算元,而不是使用 ForEach()
內部方法 ,存取集合中每個專案上的成員。
下列範例會產生相同的結果。 最後一個範例示範如何使用成員存取運算子:
PS> Get-Service -Name event* | ForEach-Object -Process { $_.DisplayName }
Windows Event Log
COM+ Event System
PS> (Get-Service -Name event*).ForEach({ $_.DisplayName })
Windows Event Log
COM+ Event System
PS> (Get-Service -Name event*).DisplayName
Windows Event Log
COM+ Event System
注意
您可以使用成員存取運算符來取得集合中專案上的屬性值,但您無法使用它直接設定它們。 如需詳細資訊,請參閱 about_Arrays。 成員存取列舉功能是一項便利功能。 各種列舉方法之間可能會有細微的行為和效能差異。
當您在該物件上使用成員存取運算元,且指定的成員存在於該物件上時,就會叫用該成員。 當您在沒有指定成員的集合物件上使用成員存取運算符時,PowerShell 會列舉該集合中的專案,並在每個列舉專案上使用成員存取運算元。
在屬性的成員存取列舉期間,運算子會針對具有該屬性的每個專案傳回 屬性的值。 如果沒有專案具有指定的 屬性,運算子會傳 $null
回 。
在方法的成員存取列舉期間,運算子會嘗試在集合中的每個專案上呼叫 方法。 如果集合中的任何項目沒有指定的方法,運算符會傳 回 MethodNotFound 例外狀況。
警告
在方法的成員存取列舉期間,會在集合中的每個專案上呼叫 方法。 如果您要呼叫的方法進行變更,則會針對集合中的每個項目進行變更。 如果列舉期間發生錯誤,方法只會在錯誤之前列舉的專案上呼叫。 如需其他安全性,請考慮手動列舉專案,並明確處理任何錯誤。
存取無法枚舉物件的成員
當您在不是可列舉集合的物件上使用成員存取運算符時,PowerShell 會叫用成員以傳回該對象的 屬性或輸出值。
PS> $MyString = 'abc'
PS> $MyString.Length
3
PS> $MyString.ToUpper()
ABC
當您在沒有成員的非可列舉物件上使用成員存取運算符時,PowerShell 會傳回遺漏屬性的 $null
或 MethodNotFound 遺漏方法的錯誤。
PS> $MyString = 'abc'
PS> $null -eq $MyString.DoesNotExist
True
PS> $MyString.DoesNotExist()
Method invocation failed because [System.String] does not contain a method named 'DoesNotExist'.
At line:1 char:1
+ $MyString.DoesNotExist()
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
存取集合對象的成員
當您在具有成員的集合物件上使用成員存取運算符時,它一律會傳回集合物件的屬性值或方法結果。
存取存在於集合中但不屬於其個別項目的成員
在此範例中,指定的成員存在於集合上,但不存在其中的專案。
PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b')
PS> $Collection.IsReadOnly
False
PS> $Collection.Add('c')
PS> $Collection
a
b
c
存取存在於集合及其項目上的成員
在此範例中,指定的成員同時存在於集合及其中的專案上。 使用集合上的成員存取運算符,將命令的結果與在 中的 ForEach-Object
集合專案上使用成員存取運算符的結果進行比較。 在集合上,運算符會傳回集合物件的屬性值或方法結果,而不是其中的專案。
PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
PS> $Collection.Count
3
PS> $Collection | ForEach-Object -Process { $_.Count }
1
1
1
PS> $Collection.ToString()
System.Collections.Generic.List`1[System.String]
PS> $Collection | ForEach-Object -Process { $_.ToString() }
a
b
c
注意
實作 System.Collections.IDictionary 介面的集合,例如 HashTable 和 OrderedDictionary,有不同的行為。 當您在具有與屬性相同名稱的字典上使用成員存取運算符時,它會傳回索引鍵的值,而不是屬性的值。
您可以使用 psbase 內部成員來存取字典物件的屬性值。 例如,如果索引鍵名稱是 keys
,而且您想要傳回 HashTable 索引鍵的集合,請使用下列語法:
$hashtable.psbase.Keys
存取存在於集合中所有項目上的成員,但不包含項目本身的成員
當您在集合物件上使用成員存取運算符時,即使集合本身沒有成員,但其中的專案有成員,PowerShell 會列舉集合中的專案,並傳回每個專案的屬性值或方法結果。
PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
PS> $Collection.Length
1
1
1
PS> $Collection.ToUpper()
A
B
C
存取集合或其元素上不存在的成員
當您在一個沒有此成員的集合物件上使用成員存取運算符時,並且其中的項目也沒有這個成員,如果您指定一個屬性,命令會返回 $null
錯誤;而如果您指定一個方法,則會返回 MethodNotFound
錯誤。
PS> [System.Collections.Generic.List[string]]$Collection = @('a', 'b', 'c')
PS> $null -eq $Collection.DoesNotExist
True
PS> $Collection.DoesNotExist()
InvalidOperation: Method invocation failed because [System.String] does not
contain a method named 'DoesNotExist'.
因為集合物件沒有成員,PowerShell 會列舉集合中的項目。 請注意,MethodNotFound 錯誤指定 System.String 不包含 方法,而不是 System.Collections.Generic.List。
只存在於集合中某些專案上的存取方法
當您使用成員存取運算符來存取集合對象上沒有方法的方法,而且集合中只有某些專案具有此方法時,命令會針對集合中沒有 方法的第一個專案傳回 MethodNotFound
錯誤。 即使在某些專案上呼叫 方法,命令仍只會傳回錯誤。
PS> @('a', 1, 'c').ToUpper()
InvalidOperation: Method invocation failed because [System.Int32] does not
contain a method named 'ToUpper'.
存取只存在於集合中某些項目的屬性
當您使用成員存取運算符來存取集合對象上沒有 屬性且只有集合中某些項目的屬性時,此命令會傳回集合中具有 屬性之每個專案的屬性值。
PS> $CapitalizedProperty = @{
MemberType = 'ScriptProperty'
Name = 'Capitalized'
Value = { $this.ToUpper() }
PassThru = $true
}
PS> [System.Collections.Generic.List[object]]$MixedCollection = @(
'a'
('b' | Add-Member @CapitalizedProperty)
('c' | Add-Member @CapitalizedProperty)
'd'
)
PS> $MixedCollection.Capitalized
B
C
存取巢狀集合的成員
當可列舉集合包含巢狀集合時,成員存取列舉會套用至每個巢狀集合。
例如,$a
是包含兩個元素的陣列:字串的巢狀陣列和單一字串。
# Get the count of items in the array.
PS> $a.Count
2
# Get the count of items in each nested item.
PS> $a.GetEnumerator().Count
2
1
# Call the ToUpper() method on all items in the nested array.
PS> $a = @(, ('bar', 'baz'), 'foo')
PS> $a.ToUpper()
BAR
BAZ
FOO
當您使用成員存取運算符時,PowerShell 會列舉 $a
中的專案,並在所有專案上呼叫 ToUpper()
方法。
筆記
如先前所述,各種列舉方法之間可能會有細微的行為和效能差異。
錯誤導致輸出遺失
當成員存取列舉因錯誤而終止時,不會傳回先前成功方法呼叫的輸出。 終止錯誤狀況包括:
- 列舉物件缺少存取的方法
- 存取的方法會引發終止錯誤
請考慮下列範例:
class Class1 { [object] Foo() { return 'Bar' } }
class Class2 { [void] Foo() { throw 'Error' } }
class Class3 {}
$example1 = ([Class1]::new(), [Class1]::new())
$example2 = ([Class1]::new(), [Class2]::new())
$example3 = ([Class1]::new(), [Class3]::new())
$example1
中的這兩個專案都有 Foo()
方法,因此方法呼叫會成功。
PS> $example1.Foo()
Bar
Bar
$example2
中第二個項目的 Foo()
方法會引發錯誤,因此遍歷會失敗。
PS> $example2.Foo()
Exception:
Line |
2 | class Class2 { [void] Foo() { throw 'Error' } }
| ~~~~~~~~~~~~~
| Error
$example2
中的第二個項目沒有 Foo()
方法,因此列舉會失敗。
PS> $example3.Foo()
InvalidOperation: Method invocation failed because [Class3] does not contain
a method named 'Foo'.
將此與使用 ForEach-Object
進行的列舉相比較
PS> $example2 | ForEach-Object -MemberName Foo
Bar
ForEach-Object: Exception calling "Foo" with "0" argument(s): "Error"
PS> $example3 | ForEach-Object -MemberName Foo
Bar
請注意,輸出會顯示已成功呼叫陣列中第一個項目的 Foo()
。
包含 PSCustomObject 實例的集合
如果物件的集合包含 PSCustomObject 項目的實例,則當存取的屬性遺失時,PowerShell 會意外地重新 $null
值。
在下列範例中,至少有一個 物件具有參考的屬性。
PS> $foo = [pscustomobject]@{ Foo = 'Foo' }
PS> $bar = [pscustomobject]@{ Bar = 'Bar' }
PS> $baz = [pscustomobject]@{ Baz = 'Baz' }
PS> ConvertTo-Json ($foo, $bar, $baz).Foo
[
"Foo",
null,
null
]
PS> ConvertTo-Json ((Get-Process -Id $PID), $foo).Name
[
"pwsh",
null
]
您預期 PowerShell 會針對指定 屬性的項目傳回單一物件。 相反地,PowerShell 也會針對沒有 屬性的每個項目傳回 $null
值。
如需此行為的詳細資訊,請參閱 PowerShell 問題 #13752。